10529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// Copyright 2014 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
50529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "chrome/browser/devtools/device/devtools_android_bridge.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <map>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <vector>
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "base/base64.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/compiler_specific.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/json/json_reader.h"
14c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/lazy_instance.h"
15558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include "base/message_loop/message_loop.h"
16c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "base/prefs/pref_service.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/threading/thread.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/values.h"
230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "chrome/browser/devtools/browser_list_tabcontents_provider.h"
24cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/browser/devtools/device/adb/adb_device_info_query.h"
25010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "chrome/browser/devtools/device/adb/adb_device_provider.h"
261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/devtools/device/port_forwarding_controller.h"
27010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "chrome/browser/devtools/device/self_device_provider.h"
28010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "chrome/browser/devtools/device/usb/usb_device_provider.h"
29bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "chrome/browser/devtools/devtools_protocol.h"
301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "chrome/browser/devtools/devtools_target_impl.h"
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/devtools/devtools_window.h"
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/profiles/profile.h"
33c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "chrome/common/pref_names.h"
34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "components/keyed_service/content/browser_context_dependency_manager.h"
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/devtools_agent_host.h"
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/public/browser/devtools_external_agent_proxy.h"
37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/public/browser/devtools_external_agent_proxy_delegate.h"
38f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "content/public/browser/user_metrics.h"
391e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "net/base/escape.h"
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using content::BrowserThread;
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
45cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const char kPageListRequest[] = "/json";
46cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const char kVersionRequest[] = "/json/version";
47cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const char kClosePageRequest[] = "/json/close/%s";
48cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const char kNewPageRequest[] = "/json/new";
49cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const char kNewPageRequestWithURL[] = "/json/new?%s";
50cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const char kActivatePageRequest[] = "/json/activate/%s";
51cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const char kBrowserTargetSocket[] = "/devtools/browser";
529ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdochconst int kAdbPollingIntervalMs = 1000;
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kUrlParam[] = "url";
5568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kPageReloadCommand[] = "Page.reload";
5668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)const char kPageNavigateCommand[] = "Page.navigate";
5768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)const int kMinVersionNewWithURL = 32;
591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)const int kNewPageNavigateDelayMs = 500;
601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// DiscoveryRequest -----------------------------------------------------
624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochclass DiscoveryRequest : public base::RefCountedThreadSafe<
640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    DiscoveryRequest,
651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    BrowserThread::DeleteOnUIThread> {
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
6746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  typedef AndroidDeviceManager::Device Device;
6846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  typedef AndroidDeviceManager::Devices Devices;
6946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  typedef AndroidDeviceManager::DeviceInfo DeviceInfo;
7046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  typedef DevToolsAndroidBridge::RemoteDevice RemoteDevice;
7146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  typedef DevToolsAndroidBridge::RemoteDevices RemoteDevices;
7246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  typedef DevToolsAndroidBridge::RemoteBrowser RemoteBrowser;
7346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  typedef DevToolsAndroidBridge::RemoteBrowsers RemoteBrowsers;
7446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  typedef base::Callback<void(const RemoteDevices&)> DiscoveryCallback;
7546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
7646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DiscoveryRequest(AndroidDeviceManager* device_manager,
7746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                   const DiscoveryCallback& callback);
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
79c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>;
800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  friend class base::DeleteHelper<DiscoveryRequest>;
810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  virtual ~DiscoveryRequest();
824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
8346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  void ReceivedDevices(const Devices& devices);
8446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  void ReceivedDeviceInfo(scoped_refptr<Device> device,
8546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                          const DeviceInfo& device_info);
8646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  void ReceivedVersion(scoped_refptr<RemoteBrowser>,
8746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                       int result,
8846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                       const std::string& response);
8946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  void ReceivedPages(scoped_refptr<RemoteBrowser>,
9046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                     int result,
9146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                     const std::string& response);
9246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
9346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DiscoveryCallback callback_;
9446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  RemoteDevices remote_devices_;
954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)};
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
970529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochDiscoveryRequest::DiscoveryRequest(
98c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    AndroidDeviceManager* device_manager,
9946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const DiscoveryCallback& callback)
10046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    : callback_(callback) {
10146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
10246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  device_manager->QueryDevices(
10346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      base::Bind(&DiscoveryRequest::ReceivedDevices, this));
1044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1060529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochDiscoveryRequest::~DiscoveryRequest() {
1074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
10846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  callback_.Run(remote_devices_);
1094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
11146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void DiscoveryRequest::ReceivedDevices(const Devices& devices) {
11246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
11346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  for (Devices::const_iterator it = devices.begin();
11446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)       it != devices.end(); ++it) {
11546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    (*it)->QueryDeviceInfo(
11646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        base::Bind(&DiscoveryRequest::ReceivedDeviceInfo, this, *it));
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
12046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void DiscoveryRequest::ReceivedDeviceInfo(scoped_refptr<Device> device,
12146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                          const DeviceInfo& device_info) {
12246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
12346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  scoped_refptr<RemoteDevice> remote_device =
12446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      new RemoteDevice(device, device_info);
12546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  remote_devices_.push_back(remote_device);
12646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  for (RemoteBrowsers::iterator it = remote_device->browsers().begin();
12746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)       it != remote_device->browsers().end(); ++it) {
12846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    (*it)->SendJsonRequest(
12946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        kVersionRequest,
13046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        base::Bind(&DiscoveryRequest::ReceivedVersion, this, *it));
13146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    (*it)->SendJsonRequest(
13246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        kPageListRequest,
13346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        base::Bind(&DiscoveryRequest::ReceivedPages, this, *it));
134f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
1354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
13746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void DiscoveryRequest::ReceivedVersion(scoped_refptr<RemoteBrowser> browser,
13846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                       int result,
1390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                       const std::string& response) {
14046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
14146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (result < 0)
1424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
1434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Parse version, append to package name if available,
1444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  scoped_ptr<base::Value> value(base::JSONReader::Read(response));
1454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  base::DictionaryValue* dict;
1464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (value && value->GetAsDictionary(&dict)) {
14746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    std::string browser_name;
14846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (dict->GetString("Browser", &browser_name)) {
1494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      std::vector<std::string> parts;
15046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      Tokenize(browser_name, "/", &parts);
151f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      if (parts.size() == 2)
15246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        browser->set_version(parts[1]);
153f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      else
15446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        browser->set_version(browser_name);
155f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
156f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    std::string package;
157f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (dict->GetString("Android-Package", &package)) {
15846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      browser->set_display_name(
15946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          AdbDeviceInfoQuery::GetDisplayName(browser->socket(), package));
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
163a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
16446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void DiscoveryRequest::ReceivedPages(scoped_refptr<RemoteBrowser> browser,
16546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                     int result,
1660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                     const std::string& response) {
16746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
16846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (result < 0)
16946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return;
17046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  scoped_ptr<base::Value> value(base::JSONReader::Read(response));
17146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  base::ListValue* list_value;
17246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (value && value->GetAsList(&list_value))
17346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    browser->SetPageDescriptors(*list_value);
1744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// ProtocolCommand ------------------------------------------------------------
177bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
1780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochclass ProtocolCommand
1790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    : public DevToolsAndroidBridge::AndroidWebSocket::Delegate {
180bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch public:
1810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  ProtocolCommand(
1820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> browser,
183bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      const std::string& debug_url,
184a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      const std::string& command,
185a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      const base::Closure callback);
186bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
187bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch private:
188bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  virtual void OnSocketOpened() OVERRIDE;
189bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  virtual void OnFrameRead(const std::string& message) OVERRIDE;
1906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  virtual void OnSocketClosed() OVERRIDE;
1916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  virtual ~ProtocolCommand();
192bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
193bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  const std::string command_;
194a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  const base::Closure callback_;
1956e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  scoped_ptr<DevToolsAndroidBridge::AndroidWebSocket> web_socket_;
196bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
1970529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DISALLOW_COPY_AND_ASSIGN(ProtocolCommand);
198bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch};
199bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
2000529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochProtocolCommand::ProtocolCommand(
2010529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> browser,
202bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    const std::string& debug_url,
203a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    const std::string& command,
204a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    const base::Closure callback)
205a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    : command_(command),
2066e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      callback_(callback),
2076e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      web_socket_(browser->CreateWebSocket(debug_url, this)) {
208bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}
209bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
2100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid ProtocolCommand::OnSocketOpened() {
211bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  web_socket_->SendFrame(command_);
212bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}
213bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
2140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid ProtocolCommand::OnFrameRead(const std::string& message) {
2156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  delete this;
216a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
217bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
2186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void ProtocolCommand::OnSocketClosed() {
219bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  delete this;
220bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}
221bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
2226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)ProtocolCommand::~ProtocolCommand() {
2236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (!callback_.is_null())
2246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    callback_.Run();
2256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
2266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
227c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace
228c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
229c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class AgentHostDelegate;
230c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
231c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)typedef std::map<std::string, AgentHostDelegate*> AgentHostDelegates;
232c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)base::LazyInstance<AgentHostDelegates>::Leaky g_host_delegates =
234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    LAZY_INSTANCE_INITIALIZER;
235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2360529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochDevToolsAndroidBridge::Wrapper::Wrapper(content::BrowserContext* context) {
2370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  bridge_ = new DevToolsAndroidBridge(Profile::FromBrowserContext(context));
2387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
2397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2400529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochDevToolsAndroidBridge::Wrapper::~Wrapper() {
2417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
2427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2430529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochDevToolsAndroidBridge* DevToolsAndroidBridge::Wrapper::Get() {
2447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return bridge_.get();
2457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
2467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// static
2480529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochDevToolsAndroidBridge::Factory* DevToolsAndroidBridge::Factory::GetInstance() {
2490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return Singleton<DevToolsAndroidBridge::Factory>::get();
2507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
2517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// static
2530529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochDevToolsAndroidBridge* DevToolsAndroidBridge::Factory::GetForProfile(
2547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    Profile* profile) {
2550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  DevToolsAndroidBridge::Wrapper* wrapper =
2560529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      static_cast<DevToolsAndroidBridge::Wrapper*>(GetInstance()->
257558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch          GetServiceForBrowserContext(profile, true));
258558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  return wrapper ? wrapper->Get() : NULL;
2597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
2607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2610529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochDevToolsAndroidBridge::Factory::Factory()
2627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    : BrowserContextKeyedServiceFactory(
2630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          "DevToolsAndroidBridge",
2647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch          BrowserContextDependencyManager::GetInstance()) {}
2657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2660529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochDevToolsAndroidBridge::Factory::~Factory() {}
2677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2680529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochKeyedService* DevToolsAndroidBridge::Factory::BuildServiceInstanceFor(
2697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    content::BrowserContext* context) const {
2700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return new DevToolsAndroidBridge::Wrapper(context);
2717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
2727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// AgentHostDelegate ----------------------------------------------------------
2754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochclass AgentHostDelegate
2770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    : public content::DevToolsExternalAgentProxyDelegate,
2780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      public DevToolsAndroidBridge::AndroidWebSocket::Delegate {
2799ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch public:
280cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  static scoped_refptr<content::DevToolsAgentHost> GetOrCreateAgentHost(
2810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      const std::string& id,
2820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> browser,
2835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      const std::string& debug_url);
2841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2851e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) private:
2869ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  AgentHostDelegate(
2879ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      const std::string& id,
2880529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> browser,
2895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      const std::string& debug_url);
2905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual ~AgentHostDelegate();
291cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  virtual void Attach(content::DevToolsExternalAgentProxy* proxy) OVERRIDE;
2925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual void Detach() OVERRIDE;
2935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual void SendMessageToBackend(
2945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      const std::string& message) OVERRIDE;
2955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual void OnSocketOpened() OVERRIDE;
2965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual void OnFrameRead(const std::string& message) OVERRIDE;
2976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  virtual void OnSocketClosed() OVERRIDE;
2989ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
2995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  const std::string id_;
3006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> browser_;
3016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  const std::string debug_url_;
3025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  bool socket_opened_;
303010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  bool is_web_view_;
3045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  std::vector<std::string> pending_messages_;
3056e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  scoped_ptr<DevToolsAndroidBridge::AndroidWebSocket> web_socket_;
306cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  content::DevToolsAgentHost* agent_host_;
307cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  content::DevToolsExternalAgentProxy* proxy_;
3085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DISALLOW_COPY_AND_ASSIGN(AgentHostDelegate);
3095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu};
3105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
3115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// static
312cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)scoped_refptr<content::DevToolsAgentHost>
313cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)AgentHostDelegate::GetOrCreateAgentHost(
3145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const std::string& id,
3155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> browser,
3165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const std::string& debug_url) {
3171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  AgentHostDelegates::iterator it = g_host_delegates.Get().find(id);
3191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (it != g_host_delegates.Get().end())
3201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return it->second->agent_host_;
3215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
3225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  AgentHostDelegate* delegate = new AgentHostDelegate(id, browser, debug_url);
323cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_refptr<content::DevToolsAgentHost> result =
324cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      content::DevToolsAgentHost::Create(delegate);
325cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  delegate->agent_host_ = result.get();
326cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return result;
3275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
3285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
3295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuAgentHostDelegate::AgentHostDelegate(
3305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const std::string& id,
3315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> browser,
3325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const std::string& debug_url)
3335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    : id_(id),
3346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      browser_(browser),
3356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      debug_url_(debug_url),
3365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      socket_opened_(false),
337cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      is_web_view_(browser->IsWebView()),
338cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      agent_host_(NULL),
339cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      proxy_(NULL) {
3405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  g_host_delegates.Get()[id] = this;
3415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
3425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
3435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuAgentHostDelegate::~AgentHostDelegate() {
3445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  g_host_delegates.Get().erase(id_);
3455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
3469ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
347cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void AgentHostDelegate::Attach(content::DevToolsExternalAgentProxy* proxy) {
348cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  proxy_ = proxy;
349010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  content::RecordAction(base::UserMetricsAction(is_web_view_ ?
350010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      "DevTools_InspectAndroidWebView" : "DevTools_InspectAndroidPage"));
3516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  web_socket_.reset(browser_->CreateWebSocket(debug_url_, this));
3525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
3539ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
3545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid AgentHostDelegate::Detach() {
3556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  web_socket_.reset();
3565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
3579ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
3585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid AgentHostDelegate::SendMessageToBackend(const std::string& message) {
3595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (socket_opened_)
3609ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    web_socket_->SendFrame(message);
3615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  else
3625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    pending_messages_.push_back(message);
3635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
364558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
3655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid AgentHostDelegate::OnSocketOpened() {
3665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  socket_opened_ = true;
3675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  for (std::vector<std::string>::iterator it = pending_messages_.begin();
3685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu       it != pending_messages_.end(); ++it) {
3695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    SendMessageToBackend(*it);
3709ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  }
3715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  pending_messages_.clear();
3725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
3739ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
3745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid AgentHostDelegate::OnFrameRead(const std::string& message) {
375cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (proxy_)
376cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      proxy_->DispatchOnClientHost(message);
3775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
378558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
3796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void AgentHostDelegate::OnSocketClosed() {
3806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (proxy_)
3815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    proxy_->ConnectionClosed();
3825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
383c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)//// RemotePageTarget ----------------------------------------------
3854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
386010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)class RemotePageTarget : public DevToolsTargetImpl,
387010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                         public DevToolsAndroidBridge::RemotePage {
3881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) public:
3890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  RemotePageTarget(scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> browser,
3901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                   const base::DictionaryValue& value);
3911e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  virtual ~RemotePageTarget();
3924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
393010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // DevToolsAndroidBridge::RemotePage implementation.
394010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  virtual DevToolsTargetImpl* GetTarget() OVERRIDE;
395010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  virtual std::string GetFrontendURL() OVERRIDE;
396010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
397010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // DevToolsTargetImpl overrides.
398f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  virtual std::string GetId() const OVERRIDE;
3991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  virtual bool IsAttached() const OVERRIDE;
4001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  virtual bool Activate() const OVERRIDE;
4011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  virtual bool Close() const OVERRIDE;
4021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  virtual void Inspect(Profile* profile) const OVERRIDE;
4031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  virtual void Reload() const OVERRIDE;
4041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
405a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  void Navigate(const std::string& url, base::Closure callback) const;
4061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
4071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) private:
4080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> browser_;
4091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  std::string debug_url_;
4101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  std::string frontend_url_;
4115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string remote_id_;
4121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  std::string remote_type_;
4131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  std::string local_id_;
4141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(RemotePageTarget);
4151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)};
4161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
417010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)static std::string GetStringProperty(const base::DictionaryValue& value,
418010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                     const std::string& name) {
419010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  std::string result;
420010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  value.GetString(name, &result);
421010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return result;
422010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
423010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
424010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)static std::string BuildUniqueTargetId(
425010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    DevToolsAndroidBridge::RemoteBrowser* browser,
426010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const base::DictionaryValue& value) {
427010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return base::StringPrintf("%s:%s:%s", browser->serial().c_str(),
428010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      browser->socket().c_str(), GetStringProperty(value, "id").c_str());
429010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
430010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
431010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)static std::string GetDebugURL(const base::DictionaryValue& value) {
432010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  std::string debug_url = GetStringProperty(value, "webSocketDebuggerUrl");
433010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
434010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (debug_url.find("ws://") == 0)
435010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    debug_url = debug_url.substr(5);
436010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  else
437010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    debug_url = "";
438010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return debug_url;
439010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
440010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
4411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)RemotePageTarget::RemotePageTarget(
4420529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> browser,
443a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    const base::DictionaryValue& value)
444010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    : DevToolsTargetImpl(AgentHostDelegate::GetOrCreateAgentHost(
445010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                             BuildUniqueTargetId(browser.get(), value),
446010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                             browser, GetDebugURL(value))),
447010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      browser_(browser),
448010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      debug_url_(GetDebugURL(value)),
4491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      remote_id_(GetStringProperty(value, "id")),
4501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      remote_type_(GetStringProperty(value, "type")),
4511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      local_id_(BuildUniqueTargetId(browser.get(), value)) {
452010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  set_type("adb_page");
453010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  set_url(GURL(GetStringProperty(value, "url")));
454010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  set_title(base::UTF16ToUTF8(net::UnescapeForHTML(base::UTF8ToUTF16(
455010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      GetStringProperty(value, "title")))));
456010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  set_description(GetStringProperty(value, "description"));
457010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  set_favicon_url(GURL(GetStringProperty(value, "faviconUrl")));
458010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  debug_url_ = GetDebugURL(value);
459010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  frontend_url_ = GetStringProperty(value, "devtoolsFrontendUrl");
4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  size_t ws_param = frontend_url_.find("?ws");
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (ws_param != std::string::npos)
4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    frontend_url_ = frontend_url_.substr(0, ws_param);
464c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (frontend_url_.find("http:") == 0)
465c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    frontend_url_ = "https:" + frontend_url_.substr(5);
4664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
4674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
4681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)RemotePageTarget::~RemotePageTarget() {
469a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
470a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
471010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)DevToolsTargetImpl* RemotePageTarget::GetTarget() {
472010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return this;
473010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
474010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
475010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)std::string RemotePageTarget::GetFrontendURL() {
476010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return frontend_url_;
477010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
478010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
479f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)std::string RemotePageTarget::GetId() const {
4801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return local_id_;
481f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
482f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
4831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)bool RemotePageTarget::IsAttached() const {
4841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return debug_url_.empty();
4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
487c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochstatic void NoOp(int, const std::string&) {}
488c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
4891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void RemotePageTarget::Inspect(Profile* profile) const {
4905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  Activate();
4911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  bool isWorker = remote_type_ == kTargetTypeWorker ||
4921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                  remote_type_ == kTargetTypeServiceWorker;
4931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DevToolsWindow::OpenExternalFrontend(profile, frontend_url_, GetAgentHost(),
4941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                       isWorker);
4951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
496bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
4971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)bool RemotePageTarget::Activate() const {
4985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string request = base::StringPrintf(kActivatePageRequest,
4995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                           remote_id_.c_str());
500c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  browser_->SendJsonRequest(request, base::Bind(&NoOp));
5011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return true;
502424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
503424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
5041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)bool RemotePageTarget::Close() const {
5055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string request = base::StringPrintf(kClosePageRequest,
5065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                           remote_id_.c_str());
507c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  browser_->SendJsonRequest(request, base::Bind(&NoOp));
5081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return true;
509bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}
510bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
5111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void RemotePageTarget::Reload() const {
512a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  browser_->SendProtocolCommand(debug_url_, kPageReloadCommand, NULL,
513a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                                base::Closure());
514bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}
515bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
516a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochvoid RemotePageTarget::Navigate(const std::string& url,
517a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                                base::Closure callback) const {
5181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  base::DictionaryValue params;
5191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  params.SetString(kUrlParam, url);
520a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  browser_->SendProtocolCommand(debug_url_, kPageNavigateCommand, &params,
521a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                                callback);
522bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}
523bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
5240529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// DevToolsAndroidBridge::RemoteBrowser ---------------------------------------
5251e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
5260529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochDevToolsAndroidBridge::RemoteBrowser::RemoteBrowser(
52746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    scoped_refptr<Device> device,
528cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const AndroidDeviceManager::BrowserInfo& browser_info)
52946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    : device_(device),
530cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      socket_(browser_info.socket_name),
531cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      display_name_(browser_info.display_name),
532cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      type_(browser_info.type),
5331e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      page_descriptors_(new base::ListValue()) {
5342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbool DevToolsAndroidBridge::RemoteBrowser::IsChrome() const {
537cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return type_ == AndroidDeviceManager::BrowserInfo::kTypeChrome;
538cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
539cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
540cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool DevToolsAndroidBridge::RemoteBrowser::IsWebView() const {
541cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return type_ == AndroidDeviceManager::BrowserInfo::kTypeWebView;
542424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
543424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
5440529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochDevToolsAndroidBridge::RemoteBrowser::ParsedVersion
5450529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochDevToolsAndroidBridge::RemoteBrowser::GetParsedVersion() const {
5461e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  ParsedVersion result;
5471e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  std::vector<std::string> parts;
5481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  Tokenize(version_, ".", &parts);
5491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  for (size_t i = 0; i != parts.size(); ++i) {
5501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    int value = 0;
5511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    base::StringToInt(parts[i], &value);
5521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    result.push_back(value);
5531e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
5541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return result;
555424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
556424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
557010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)std::vector<DevToolsAndroidBridge::RemotePage*>
558010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)DevToolsAndroidBridge::RemoteBrowser::CreatePages() {
559010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  std::vector<DevToolsAndroidBridge::RemotePage*> result;
5601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  for (size_t i = 0; i < page_descriptors_->GetSize(); ++i) {
5611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    base::Value* item;
5621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    page_descriptors_->Get(i, &item);
5631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    if (!item)
5641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      continue;
5651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    base::DictionaryValue* dict;
5661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    if (!item->GetAsDictionary(&dict))
5671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      continue;
5681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    result.push_back(new RemotePageTarget(this, *dict));
569424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
5701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return result;
571424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
572424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
5730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid DevToolsAndroidBridge::RemoteBrowser::SetPageDescriptors(
5741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    const base::ListValue& list) {
5751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  page_descriptors_.reset(list.DeepCopy());
5761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
5774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
578c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochstatic void RespondOnUIThread(
57946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const DevToolsAndroidBridge::JsonRequestCallback& callback,
580c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    int result,
581c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const std::string& response) {
582a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (callback.is_null())
583a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    return;
584c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  BrowserThread::PostTask(
585c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      BrowserThread::UI, FROM_HERE, base::Bind(callback, result, response));
5861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
5874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
5880529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid DevToolsAndroidBridge::RemoteBrowser::SendJsonRequest(
589c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const std::string& request, const JsonRequestCallback& callback) {
59046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  device_->SendJsonRequest(socket_, request, callback);
591a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
592a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
5930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid DevToolsAndroidBridge::RemoteBrowser::SendProtocolCommand(
5941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    const std::string& debug_url,
5951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    const std::string& method,
596a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    base::DictionaryValue* params,
597a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    const base::Closure callback) {
5981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
5991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (debug_url.empty())
6001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return;
6011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  DevToolsProtocol::Command command(1, method, params);
6020529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  new ProtocolCommand(this, debug_url, command.Serialize(), callback);
6031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
6041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
6055c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid DevToolsAndroidBridge::RemoteBrowser::Open(
6065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const std::string& url,
607010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const DevToolsAndroidBridge::RemotePageCallback& callback) {
608a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
6095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  InnerOpen(url, base::Bind(&RemoteBrowser::RespondToOpenOnUIThread,
6105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                            this, callback));
611a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
612a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
613cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)scoped_refptr<content::DevToolsAgentHost>
614cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)DevToolsAndroidBridge::RemoteBrowser::GetAgentHost() {
615cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return AgentHostDelegate::GetOrCreateAgentHost(
61646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      "adb:" + device_->serial() + ":" + socket_, this, kBrowserTargetSocket);
61746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
61846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
6196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)DevToolsAndroidBridge::AndroidWebSocket*
62046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)DevToolsAndroidBridge::RemoteBrowser::CreateWebSocket(
62146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const std::string& url,
62246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    DevToolsAndroidBridge::AndroidWebSocket::Delegate* delegate) {
62346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return device_->CreateWebSocket(socket_, url, delegate);
624cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
625cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
6265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid DevToolsAndroidBridge::RemoteBrowser::RespondToOpenOnUIThread(
627010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const DevToolsAndroidBridge::RemotePageCallback& callback,
6285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    int result,
6295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    const std::string& response) {
630a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
6315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (result < 0) {
6325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    callback.Run(NULL);
6335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return;
6345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
6355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  scoped_ptr<base::Value> value(base::JSONReader::Read(response));
6365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  base::DictionaryValue* dict;
6375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (value && value->GetAsDictionary(&dict)) {
638010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    RemotePageTarget* new_page = new RemotePageTarget(this, *dict);
639010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    callback.Run(new_page);
6405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
641a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
642a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
6435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid DevToolsAndroidBridge::RemoteBrowser::InnerOpen(
644a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    const std::string& input_url,
645a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    const JsonRequestCallback& callback) {
646a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
647f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  GURL gurl(input_url);
648f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!gurl.is_valid()) {
649f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    gurl = GURL("http://" + input_url);
650f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (!gurl.is_valid())
651f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)     return;
652f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
653f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  std::string url = gurl.spec();
654f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
6551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  ParsedVersion parsed_version = GetParsedVersion();
6561e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (IsChrome() &&
6571e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      !parsed_version.empty() &&
6581e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      parsed_version[0] >= kMinVersionNewWithURL) {
6591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    std::string query = net::EscapeQueryParamValue(url, false /* use_plus */);
6601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    std::string request =
6611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        base::StringPrintf(kNewPageRequestWithURL, query.c_str());
662a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    SendJsonRequest(request, callback);
6631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  } else {
664c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    SendJsonRequest(kNewPageRequest,
665a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        base::Bind(&RemoteBrowser::PageCreatedOnUIThread, this,
666a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                   callback, url));
667a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  }
668a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
669a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
6700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid DevToolsAndroidBridge::RemoteBrowser::PageCreatedOnUIThread(
671a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    const JsonRequestCallback& callback,
672bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    const std::string& url, int result, const std::string& response) {
673a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
674a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
675bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  if (result < 0)
676bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    return;
6771e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // Navigating too soon after the page creation breaks navigation history
6781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  // (crbug.com/311014). This can be avoided by adding a moderate delay.
6791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  BrowserThread::PostDelayedTask(
680bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      BrowserThread::UI, FROM_HERE,
681a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      base::Bind(&RemoteBrowser::NavigatePageOnUIThread,
682a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                 this, callback, result, response, url),
6831e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      base::TimeDelta::FromMilliseconds(kNewPageNavigateDelayMs));
684bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}
685bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
6860529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid DevToolsAndroidBridge::RemoteBrowser::NavigatePageOnUIThread(
687a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    const JsonRequestCallback& callback,
688a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    int result, const std::string& response, const std::string& url) {
689a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
690bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  scoped_ptr<base::Value> value(base::JSONReader::Read(response));
691bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  base::DictionaryValue* dict;
692a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
693bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  if (value && value->GetAsDictionary(&dict)) {
6941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    RemotePageTarget new_page(this, *dict);
695a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    new_page.Navigate(url,
696a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        base::Bind(&RespondOnUIThread, callback, result, response));
697bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  }
698bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}
699bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
7000529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochDevToolsAndroidBridge::RemoteBrowser::~RemoteBrowser() {
701a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
702a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
7030529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// DevToolsAndroidBridge::RemoteDevice ----------------------------------------
7044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
7050529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochDevToolsAndroidBridge::RemoteDevice::RemoteDevice(
70646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    scoped_refptr<AndroidDeviceManager::Device> device,
70746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const AndroidDeviceManager::DeviceInfo& device_info)
70846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    : device_(device),
709cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      model_(device_info.model),
71046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      connected_(device_info.connected),
711cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      screen_size_(device_info.screen_size) {
712cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  for (std::vector<AndroidDeviceManager::BrowserInfo>::const_iterator it =
713cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      device_info.browser_info.begin();
714cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      it != device_info.browser_info.end();
715cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      ++it) {
71646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    browsers_.push_back(new DevToolsAndroidBridge::RemoteBrowser(device, *it));
717cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
7184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
7194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
7200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid DevToolsAndroidBridge::RemoteDevice::OpenSocket(
721c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const std::string& socket_name,
722c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    const AndroidDeviceManager::SocketCallback& callback) {
72346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  device_->OpenSocket(socket_name, callback);
7244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
7254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
7260529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochDevToolsAndroidBridge::RemoteDevice::~RemoteDevice() {
7274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
7284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
7290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// DevToolsAndroidBridge ------------------------------------------------------
7304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
7310529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochDevToolsAndroidBridge::DevToolsAndroidBridge(Profile* profile)
732c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    : profile_(profile),
73346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      device_manager_(AndroidDeviceManager::Create()),
7341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      task_scheduler_(base::Bind(&DevToolsAndroidBridge::ScheduleTaskDefault)),
7351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      port_forwarding_controller_(new PortForwardingController(profile)) {
736c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
737c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  pref_change_registrar_.Init(profile_->GetPrefs());
738a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  pref_change_registrar_.Add(prefs::kDevToolsDiscoverUsbDevicesEnabled,
7390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      base::Bind(&DevToolsAndroidBridge::CreateDeviceProviders,
740c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                 base::Unretained(this)));
741c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  CreateDeviceProviders();
742effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
743effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
7440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid DevToolsAndroidBridge::AddDeviceListListener(
7450529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    DeviceListListener* listener) {
746ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
7471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  bool polling_was_off = !NeedsDeviceListPolling();
748a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  device_list_listeners_.push_back(listener);
7491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (polling_was_off)
75046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    StartDeviceListPolling();
7519ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
7529ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
7530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid DevToolsAndroidBridge::RemoveDeviceListListener(
7540529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    DeviceListListener* listener) {
755ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
756a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  DeviceListListeners::iterator it = std::find(
757a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      device_list_listeners_.begin(), device_list_listeners_.end(), listener);
758a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  DCHECK(it != device_list_listeners_.end());
759a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  device_list_listeners_.erase(it);
7601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!NeedsDeviceListPolling())
76146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    StopDeviceListPolling();
7629ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
7639ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
7640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid DevToolsAndroidBridge::AddDeviceCountListener(
7650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    DeviceCountListener* listener) {
766a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  device_count_listeners_.push_back(listener);
76746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (device_count_listeners_.size() == 1)
76846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    StartDeviceCountPolling();
769a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
770a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
7710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid DevToolsAndroidBridge::RemoveDeviceCountListener(
772a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    DeviceCountListener* listener) {
773a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
774a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  DeviceCountListeners::iterator it = std::find(
775a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      device_count_listeners_.begin(), device_count_listeners_.end(), listener);
776a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  DCHECK(it != device_count_listeners_.end());
777a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  device_count_listeners_.erase(it);
77846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (device_count_listeners_.empty())
77946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    StopDeviceCountPolling();
780a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
781a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
7821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid DevToolsAndroidBridge::AddPortForwardingListener(
7831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    PortForwardingListener* listener) {
7841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  bool polling_was_off = !NeedsDeviceListPolling();
7851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  port_forwarding_listeners_.push_back(listener);
7861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (polling_was_off)
7871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    StartDeviceListPolling();
7881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
7891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
7901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid DevToolsAndroidBridge::RemovePortForwardingListener(
7911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    PortForwardingListener* listener) {
7921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  PortForwardingListeners::iterator it = std::find(
7931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      port_forwarding_listeners_.begin(),
7941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      port_forwarding_listeners_.end(),
7951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      listener);
7961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(it != port_forwarding_listeners_.end());
7971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  port_forwarding_listeners_.erase(it);
7981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!NeedsDeviceListPolling())
7991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    StopDeviceListPolling();
8001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
8011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
802c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// static
8030529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochbool DevToolsAndroidBridge::HasDevToolsWindow(const std::string& agent_id) {
8041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
8051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return g_host_delegates.Get().find(agent_id) != g_host_delegates.Get().end();
806558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
807558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
8080529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochDevToolsAndroidBridge::~DevToolsAndroidBridge() {
8097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
810a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  DCHECK(device_list_listeners_.empty());
811a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  DCHECK(device_count_listeners_.empty());
8121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(port_forwarding_listeners_.empty());
8137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
8147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
81546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void DevToolsAndroidBridge::StartDeviceListPolling() {
81646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  device_list_callback_.Reset(
81746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    base::Bind(&DevToolsAndroidBridge::ReceivedDeviceList, this));
81846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  RequestDeviceList(device_list_callback_.callback());
81946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
8201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
82146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void DevToolsAndroidBridge::StopDeviceListPolling() {
82246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  device_list_callback_.Cancel();
82346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  devices_.clear();
8249ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
8259ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
8261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool DevToolsAndroidBridge::NeedsDeviceListPolling() {
8271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return !device_list_listeners_.empty() || !port_forwarding_listeners_.empty();
8281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
8291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
83046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void DevToolsAndroidBridge::RequestDeviceList(
83146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const base::Callback<void(const RemoteDevices&)>& callback) {
832c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
83346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
8341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!NeedsDeviceListPolling() ||
83546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      !callback.Equals(device_list_callback_.callback()))
83646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return;
83746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
83846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  new DiscoveryRequest(device_manager_.get(), callback);
839c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
840c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
84146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void DevToolsAndroidBridge::ReceivedDeviceList(const RemoteDevices& devices) {
8429ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
8439ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
84446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DeviceListListeners copy(device_list_listeners_);
84546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  for (DeviceListListeners::iterator it = copy.begin(); it != copy.end(); ++it)
84646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    (*it)->DeviceListChanged(devices);
847a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
8481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DevicesStatus status =
8491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      port_forwarding_controller_->DeviceListChanged(devices);
8501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  PortForwardingListeners forwarding_listeners(port_forwarding_listeners_);
8511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  for (PortForwardingListeners::iterator it = forwarding_listeners.begin();
8521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci       it != forwarding_listeners.end(); ++it) {
8531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    (*it)->PortStatusChanged(status);
8541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
8551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
8561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!NeedsDeviceListPolling())
857a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    return;
858a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
85946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  devices_ = devices;
8609ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
86146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  task_scheduler_.Run(
86246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      base::Bind(&DevToolsAndroidBridge::RequestDeviceList,
86346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                 this, device_list_callback_.callback()));
86446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
86546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
86646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void DevToolsAndroidBridge::StartDeviceCountPolling() {
86746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  device_count_callback_.Reset(
86846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      base::Bind(&DevToolsAndroidBridge::ReceivedDeviceCount, this));
86946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  RequestDeviceCount(device_count_callback_.callback());
87046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
87146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
87246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void DevToolsAndroidBridge::StopDeviceCountPolling() {
87346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  device_count_callback_.Cancel();
874a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
875a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
87646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void DevToolsAndroidBridge::RequestDeviceCount(
87746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const base::Callback<void(int)>& callback) {
878a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
879a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
88046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (device_count_listeners_.empty() ||
88146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      !callback.Equals(device_count_callback_.callback()))
8829ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    return;
8839ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
88446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  UsbDeviceProvider::CountDevices(callback);
885a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
886a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
8870529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid DevToolsAndroidBridge::ReceivedDeviceCount(int count) {
888a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
889a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
890a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  DeviceCountListeners copy(device_count_listeners_);
891a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  for (DeviceCountListeners::iterator it = copy.begin(); it != copy.end(); ++it)
892a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    (*it)->DeviceCountChanged(count);
893a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
89446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (device_count_listeners_.empty())
89546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)     return;
89646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
89746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  task_scheduler_.Run(
89846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      base::Bind(&DevToolsAndroidBridge::RequestDeviceCount,
89946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                 this, device_count_callback_.callback()));
90046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
90146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
90246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// static
90346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void DevToolsAndroidBridge::ScheduleTaskDefault(const base::Closure& task) {
9049ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch  BrowserThread::PostDelayedTask(
9059ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      BrowserThread::UI,
9069ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      FROM_HERE,
90746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      task,
9089ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      base::TimeDelta::FromMilliseconds(kAdbPollingIntervalMs));
9099ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch}
910c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
9110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid DevToolsAndroidBridge::CreateDeviceProviders() {
91246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  AndroidDeviceManager::DeviceProviders device_providers;
913c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#if defined(DEBUG_DEVTOOLS)
9140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  BrowserListTabContentsProvider::EnableTethering();
9150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // We cannot rely on command line switch here as we might want to connect
9160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // to another instance of Chrome. Using hard-coded port number instead.
9170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  const int kDefaultDebuggingPort = 9222;
91846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  device_providers.push_back(new SelfAsDeviceProvider(kDefaultDebuggingPort));
919c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#endif
92046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  device_providers.push_back(new AdbDeviceProvider());
921c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
922c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  PrefService* service = profile_->GetPrefs();
923c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  const PrefService::Preference* pref =
924c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      service->FindPreference(prefs::kDevToolsDiscoverUsbDevicesEnabled);
925c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  const base::Value* pref_value = pref->GetValue();
926c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
927c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  bool enabled;
928c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (pref_value->GetAsBoolean(&enabled) && enabled) {
92946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    device_providers.push_back(new UsbDeviceProvider(profile_));
93046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
93146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  device_manager_->SetDeviceProviders(device_providers);
9321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (NeedsDeviceListPolling()) {
93346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    StopDeviceListPolling();
93446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    StartDeviceListPolling();
935c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
936c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
937