Home | History | Annotate | Download | only in webui
      1 // Copyright (c) 2012 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/ui/webui/inspect_ui.h"
      6 
      7 #include "base/prefs/pref_service.h"
      8 #include "base/stl_util.h"
      9 #include "chrome/browser/devtools/devtools_adb_bridge.h"
     10 #include "chrome/browser/devtools/devtools_targets_ui.h"
     11 #include "chrome/browser/profiles/profile.h"
     12 #include "chrome/browser/ui/browser_navigator.h"
     13 #include "chrome/browser/ui/singleton_tabs.h"
     14 #include "chrome/browser/ui/webui/theme_source.h"
     15 #include "chrome/common/pref_names.h"
     16 #include "chrome/common/url_constants.h"
     17 #include "content/public/browser/notification_service.h"
     18 #include "content/public/browser/notification_source.h"
     19 #include "content/public/browser/notification_types.h"
     20 #include "content/public/browser/user_metrics.h"
     21 #include "content/public/browser/web_contents.h"
     22 #include "content/public/browser/web_ui.h"
     23 #include "content/public/browser/web_ui_data_source.h"
     24 #include "content/public/browser/web_ui_message_handler.h"
     25 #include "grit/browser_resources.h"
     26 
     27 using content::WebContents;
     28 using content::WebUIMessageHandler;
     29 
     30 namespace {
     31 
     32 const char kInitUICommand[]  = "init-ui";
     33 const char kInspectCommand[]  = "inspect";
     34 const char kActivateCommand[]  = "activate";
     35 const char kCloseCommand[]  = "close";
     36 const char kReloadCommand[]  = "reload";
     37 const char kOpenCommand[]  = "open";
     38 
     39 const char kDiscoverUsbDevicesEnabledCommand[] =
     40     "set-discover-usb-devices-enabled";
     41 const char kPortForwardingEnabledCommand[] =
     42     "set-port-forwarding-enabled";
     43 const char kPortForwardingConfigCommand[] = "set-port-forwarding-config";
     44 
     45 const char kPortForwardingDefaultPort[] = "8080";
     46 const char kPortForwardingDefaultLocation[] = "localhost:8080";
     47 
     48 class InspectMessageHandler : public WebUIMessageHandler {
     49  public:
     50   explicit InspectMessageHandler(InspectUI* inspect_ui)
     51       : inspect_ui_(inspect_ui) {}
     52   virtual ~InspectMessageHandler() {}
     53 
     54  private:
     55   // WebUIMessageHandler implementation.
     56   virtual void RegisterMessages() OVERRIDE;
     57 
     58   void HandleInitUICommand(const ListValue* args);
     59   void HandleInspectCommand(const ListValue* args);
     60   void HandleActivateCommand(const ListValue* args);
     61   void HandleCloseCommand(const ListValue* args);
     62   void HandleReloadCommand(const ListValue* args);
     63   void HandleOpenCommand(const ListValue* args);
     64   void HandleBooleanPrefChanged(const char* pref_name,
     65                                 const ListValue* args);
     66   void HandlePortForwardingConfigCommand(const ListValue* args);
     67 
     68   InspectUI* inspect_ui_;
     69 
     70   DISALLOW_COPY_AND_ASSIGN(InspectMessageHandler);
     71 };
     72 
     73 void InspectMessageHandler::RegisterMessages() {
     74   web_ui()->RegisterMessageCallback(kInitUICommand,
     75       base::Bind(&InspectMessageHandler::HandleInitUICommand,
     76                  base::Unretained(this)));
     77   web_ui()->RegisterMessageCallback(kInspectCommand,
     78       base::Bind(&InspectMessageHandler::HandleInspectCommand,
     79                  base::Unretained(this)));
     80   web_ui()->RegisterMessageCallback(kActivateCommand,
     81       base::Bind(&InspectMessageHandler::HandleActivateCommand,
     82                  base::Unretained(this)));
     83   web_ui()->RegisterMessageCallback(kCloseCommand,
     84       base::Bind(&InspectMessageHandler::HandleCloseCommand,
     85                  base::Unretained(this)));
     86   web_ui()->RegisterMessageCallback(kDiscoverUsbDevicesEnabledCommand,
     87       base::Bind(&InspectMessageHandler::HandleBooleanPrefChanged,
     88                   base::Unretained(this),
     89                   &prefs::kDevToolsDiscoverUsbDevicesEnabled[0]));
     90   web_ui()->RegisterMessageCallback(kPortForwardingEnabledCommand,
     91       base::Bind(&InspectMessageHandler::HandleBooleanPrefChanged,
     92                  base::Unretained(this),
     93                  &prefs::kDevToolsPortForwardingEnabled[0]));
     94   web_ui()->RegisterMessageCallback(kPortForwardingConfigCommand,
     95       base::Bind(&InspectMessageHandler::HandlePortForwardingConfigCommand,
     96                  base::Unretained(this)));
     97   web_ui()->RegisterMessageCallback(kReloadCommand,
     98       base::Bind(&InspectMessageHandler::HandleReloadCommand,
     99                  base::Unretained(this)));
    100   web_ui()->RegisterMessageCallback(kOpenCommand,
    101       base::Bind(&InspectMessageHandler::HandleOpenCommand,
    102                  base::Unretained(this)));
    103 }
    104 
    105 void InspectMessageHandler::HandleInitUICommand(const ListValue*) {
    106   inspect_ui_->InitUI();
    107 }
    108 
    109 static bool ParseStringArgs(const ListValue* args,
    110                             std::string* arg0,
    111                             std::string* arg1,
    112                             std::string* arg2 = 0) {
    113   int arg_size = args->GetSize();
    114   return (!arg0 || (arg_size > 0 && args->GetString(0, arg0))) &&
    115          (!arg1 || (arg_size > 1 && args->GetString(1, arg1))) &&
    116          (!arg2 || (arg_size > 2 && args->GetString(2, arg2)));
    117 }
    118 
    119 void InspectMessageHandler::HandleInspectCommand(const ListValue* args) {
    120   std::string source;
    121   std::string id;
    122   if (ParseStringArgs(args, &source, &id))
    123     inspect_ui_->Inspect(source, id);
    124 }
    125 
    126 void InspectMessageHandler::HandleActivateCommand(const ListValue* args) {
    127   std::string source;
    128   std::string id;
    129   if (ParseStringArgs(args, &source, &id))
    130     inspect_ui_->Activate(source, id);
    131 }
    132 
    133 void InspectMessageHandler::HandleCloseCommand(const ListValue* args) {
    134   std::string source;
    135   std::string id;
    136   if (ParseStringArgs(args, &source, &id))
    137     inspect_ui_->Close(source, id);
    138 }
    139 
    140 void InspectMessageHandler::HandleReloadCommand(const ListValue* args) {
    141   std::string source;
    142   std::string id;
    143   if (ParseStringArgs(args, &source, &id))
    144     inspect_ui_->Reload(source, id);
    145 }
    146 
    147 void InspectMessageHandler::HandleOpenCommand(const ListValue* args) {
    148   std::string source_id;
    149   std::string browser_id;
    150   std::string url;
    151   if (ParseStringArgs(args, &source_id, &browser_id, &url))
    152     inspect_ui_->Open(source_id, browser_id, url);
    153 }
    154 
    155 void InspectMessageHandler::HandleBooleanPrefChanged(
    156     const char* pref_name,
    157     const ListValue* args) {
    158   Profile* profile = Profile::FromWebUI(web_ui());
    159   if (!profile)
    160     return;
    161 
    162   bool enabled;
    163   if (args->GetSize() == 1 && args->GetBoolean(0, &enabled))
    164     profile->GetPrefs()->SetBoolean(pref_name, enabled);
    165 }
    166 
    167 void InspectMessageHandler::HandlePortForwardingConfigCommand(
    168     const ListValue* args) {
    169   Profile* profile = Profile::FromWebUI(web_ui());
    170   if (!profile)
    171     return;
    172 
    173   const DictionaryValue* dict_src;
    174   if (args->GetSize() == 1 && args->GetDictionary(0, &dict_src))
    175     profile->GetPrefs()->Set(prefs::kDevToolsPortForwardingConfig, *dict_src);
    176 }
    177 
    178 }  // namespace
    179 
    180 InspectUI::InspectUI(content::WebUI* web_ui)
    181     : WebUIController(web_ui) {
    182   web_ui->AddMessageHandler(new InspectMessageHandler(this));
    183   Profile* profile = Profile::FromWebUI(web_ui);
    184   content::WebUIDataSource::Add(profile, CreateInspectUIHTMLSource());
    185 
    186   // Set up the chrome://theme/ source.
    187   ThemeSource* theme = new ThemeSource(profile);
    188   content::URLDataSource::Add(profile, theme);
    189 }
    190 
    191 InspectUI::~InspectUI() {
    192   StopListeningNotifications();
    193 }
    194 
    195 void InspectUI::InitUI() {
    196   SetPortForwardingDefaults();
    197   StartListeningNotifications();
    198   UpdateDiscoverUsbDevicesEnabled();
    199   UpdatePortForwardingEnabled();
    200   UpdatePortForwardingConfig();
    201 }
    202 
    203 void InspectUI::Inspect(const std::string& source_id,
    204                         const std::string& target_id) {
    205   DevToolsTargetsUIHandler* handler = FindTargetHandler(source_id);
    206   if (handler)
    207     handler->Inspect(target_id, Profile::FromWebUI(web_ui()));
    208 }
    209 
    210 void InspectUI::Activate(const std::string& source_id,
    211                          const std::string& target_id) {
    212   DevToolsTargetsUIHandler* handler = FindTargetHandler(source_id);
    213   if (handler)
    214     handler->Activate(target_id);
    215 }
    216 
    217 void InspectUI::Close(const std::string& source_id,
    218                       const std::string& target_id) {
    219   DevToolsTargetsUIHandler* handler = FindTargetHandler(source_id);
    220   if (handler)
    221     handler->Close(target_id);
    222 }
    223 
    224 void InspectUI::Reload(const std::string& source_id,
    225                        const std::string& target_id) {
    226   DevToolsTargetsUIHandler* handler = FindTargetHandler(source_id);
    227   if (handler)
    228     handler->Reload(target_id);
    229 }
    230 
    231 void InspectUI::Open(const std::string& source_id,
    232                      const std::string& browser_id,
    233                      const std::string& url) {
    234   DevToolsRemoteTargetsUIHandler* handler = FindRemoteTargetHandler(source_id);
    235   if (handler)
    236     handler->Open(browser_id, url);
    237 }
    238 
    239 void InspectUI::InspectDevices(Browser* browser) {
    240   content::RecordAction(content::UserMetricsAction("InspectDevices"));
    241   chrome::NavigateParams params(chrome::GetSingletonTabNavigateParams(
    242       browser, GURL(chrome::kChromeUIInspectURL)));
    243   params.path_behavior = chrome::NavigateParams::IGNORE_AND_NAVIGATE;
    244   ShowSingletonTabOverwritingNTP(browser, params);
    245 }
    246 
    247 void InspectUI::Observe(int type,
    248     const content::NotificationSource& source,
    249     const content::NotificationDetails& details) {
    250   if (source == content::Source<WebContents>(web_ui()->GetWebContents()))
    251     StopListeningNotifications();
    252 }
    253 
    254 void InspectUI::StartListeningNotifications() {
    255   if (!target_handlers_.empty())  // Possible when reloading the page.
    256     StopListeningNotifications();
    257 
    258   Profile* profile = Profile::FromWebUI(web_ui());
    259 
    260   DevToolsTargetsUIHandler::Callback callback =
    261       base::Bind(&InspectUI::PopulateTargets, base::Unretained(this));
    262 
    263   AddTargetUIHandler(
    264       DevToolsTargetsUIHandler::CreateForRenderers(callback));
    265   AddTargetUIHandler(
    266       DevToolsTargetsUIHandler::CreateForWorkers(callback));
    267   AddRemoteTargetUIHandler(
    268       DevToolsRemoteTargetsUIHandler::CreateForAdb(callback, profile));
    269 
    270   notification_registrar_.Add(this,
    271                               content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
    272                               content::NotificationService::AllSources());
    273 
    274   pref_change_registrar_.Init(profile->GetPrefs());
    275   pref_change_registrar_.Add(prefs::kDevToolsDiscoverUsbDevicesEnabled,
    276       base::Bind(&InspectUI::UpdateDiscoverUsbDevicesEnabled,
    277                  base::Unretained(this)));
    278   pref_change_registrar_.Add(prefs::kDevToolsPortForwardingEnabled,
    279       base::Bind(&InspectUI::UpdatePortForwardingEnabled,
    280                  base::Unretained(this)));
    281   pref_change_registrar_.Add(prefs::kDevToolsPortForwardingConfig,
    282       base::Bind(&InspectUI::UpdatePortForwardingConfig,
    283                  base::Unretained(this)));
    284 }
    285 
    286 void InspectUI::StopListeningNotifications() {
    287   if (target_handlers_.empty())
    288     return;
    289 
    290   STLDeleteValues(&target_handlers_);
    291   STLDeleteValues(&remote_target_handlers_);
    292 
    293   notification_registrar_.RemoveAll();
    294   pref_change_registrar_.RemoveAll();
    295 }
    296 
    297 content::WebUIDataSource* InspectUI::CreateInspectUIHTMLSource() {
    298   content::WebUIDataSource* source =
    299       content::WebUIDataSource::Create(chrome::kChromeUIInspectHost);
    300   source->AddResourcePath("inspect.css", IDR_INSPECT_CSS);
    301   source->AddResourcePath("inspect.js", IDR_INSPECT_JS);
    302   source->SetDefaultResource(IDR_INSPECT_HTML);
    303   return source;
    304 }
    305 
    306 void InspectUI::UpdateDiscoverUsbDevicesEnabled() {
    307   const Value* value = GetPrefValue(prefs::kDevToolsDiscoverUsbDevicesEnabled);
    308   web_ui()->CallJavascriptFunction("updateDiscoverUsbDevicesEnabled", *value);
    309 
    310   // Configure adb bridge.
    311   Profile* profile = Profile::FromWebUI(web_ui());
    312   DevToolsAdbBridge* adb_bridge =
    313       DevToolsAdbBridge::Factory::GetForProfile(profile);
    314   if (adb_bridge) {
    315     bool enabled = false;
    316     value->GetAsBoolean(&enabled);
    317 
    318     DevToolsAdbBridge::DeviceProviders device_providers;
    319     device_providers.push_back(AndroidDeviceProvider::GetAdbDeviceProvider());
    320 
    321     if (enabled) {
    322       device_providers.push_back(
    323           AndroidDeviceProvider::GetUsbDeviceProvider(profile));
    324     }
    325 
    326     adb_bridge->set_device_providers(device_providers);
    327   }
    328 }
    329 
    330 void InspectUI::UpdatePortForwardingEnabled() {
    331   web_ui()->CallJavascriptFunction("updatePortForwardingEnabled",
    332       *GetPrefValue(prefs::kDevToolsPortForwardingEnabled));
    333 
    334 }
    335 
    336 void InspectUI::UpdatePortForwardingConfig() {
    337   web_ui()->CallJavascriptFunction("updatePortForwardingConfig",
    338       *GetPrefValue(prefs::kDevToolsPortForwardingConfig));
    339 }
    340 
    341 void InspectUI::SetPortForwardingDefaults() {
    342   Profile* profile = Profile::FromWebUI(web_ui());
    343   PrefService* prefs = profile->GetPrefs();
    344 
    345   bool default_set;
    346   if (!GetPrefValue(prefs::kDevToolsPortForwardingDefaultSet)->
    347       GetAsBoolean(&default_set) || default_set) {
    348     return;
    349   }
    350 
    351   // This is the first chrome://inspect invocation on a fresh profile or after
    352   // upgrade from a version that did not have kDevToolsPortForwardingDefaultSet.
    353   prefs->SetBoolean(prefs::kDevToolsPortForwardingDefaultSet, true);
    354 
    355   bool enabled;
    356   const base::DictionaryValue* config;
    357   if (!GetPrefValue(prefs::kDevToolsPortForwardingEnabled)->
    358         GetAsBoolean(&enabled) ||
    359       !GetPrefValue(prefs::kDevToolsPortForwardingConfig)->
    360         GetAsDictionary(&config)) {
    361     return;
    362   }
    363 
    364   // Do nothing if user already took explicit action.
    365   if (enabled || config->size() != 0)
    366     return;
    367 
    368   base::DictionaryValue default_config;
    369   default_config.SetString(
    370       kPortForwardingDefaultPort, kPortForwardingDefaultLocation);
    371   prefs->Set(prefs::kDevToolsPortForwardingConfig, default_config);
    372 }
    373 
    374 const base::Value* InspectUI::GetPrefValue(const char* name) {
    375   Profile* profile = Profile::FromWebUI(web_ui());
    376   return profile->GetPrefs()->FindPreference(name)->GetValue();
    377 }
    378 
    379 void InspectUI::AddTargetUIHandler(
    380     scoped_ptr<DevToolsTargetsUIHandler> handler) {
    381   DevToolsTargetsUIHandler* handler_ptr = handler.release();
    382   target_handlers_[handler_ptr->source_id()] = handler_ptr;
    383 }
    384 
    385 void InspectUI::AddRemoteTargetUIHandler(
    386     scoped_ptr<DevToolsRemoteTargetsUIHandler> handler) {
    387   DevToolsRemoteTargetsUIHandler* handler_ptr = handler.release();
    388   remote_target_handlers_[handler_ptr->source_id()] = handler_ptr;
    389 }
    390 
    391 DevToolsTargetsUIHandler* InspectUI::FindTargetHandler(
    392     const std::string& source_id) {
    393   TargetHandlerMap::iterator it = target_handlers_.find(source_id);
    394   return it != target_handlers_.end() ?
    395          it->second :
    396          FindRemoteTargetHandler(source_id);
    397 }
    398 
    399 DevToolsRemoteTargetsUIHandler* InspectUI::FindRemoteTargetHandler(
    400     const std::string& source_id) {
    401   RemoteTargetHandlerMap::iterator it = remote_target_handlers_.find(source_id);
    402   return it != remote_target_handlers_.end() ? it->second : NULL;
    403 }
    404 
    405 void InspectUI::PopulateTargets(const std::string& source,
    406                                 scoped_ptr<base::ListValue> targets) {
    407   scoped_ptr<base::Value> source_value(base::Value::CreateStringValue(source));
    408   web_ui()->CallJavascriptFunction(
    409       "populateTargets",
    410       *source_value.get(),
    411       *targets.get());
    412 }
    413