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/test/chromedriver/chrome/chrome_impl.h"
6
7#include "chrome/test/chromedriver/chrome/devtools_client.h"
8#include "chrome/test/chromedriver/chrome/devtools_event_listener.h"
9#include "chrome/test/chromedriver/chrome/devtools_http_client.h"
10#include "chrome/test/chromedriver/chrome/status.h"
11#include "chrome/test/chromedriver/chrome/web_view_impl.h"
12#include "chrome/test/chromedriver/net/port_server.h"
13
14ChromeImpl::~ChromeImpl() {
15  if (!quit_)
16    port_reservation_->Leak();
17}
18
19ChromeDesktopImpl* ChromeImpl::GetAsDesktop() {
20  return NULL;
21}
22
23const BrowserInfo* ChromeImpl::GetBrowserInfo() {
24  return devtools_http_client_->browser_info();
25}
26
27bool ChromeImpl::HasCrashedWebView() {
28  for (WebViewList::iterator it = web_views_.begin();
29       it != web_views_.end(); ++it) {
30    if ((*it)->WasCrashed())
31      return true;
32  }
33  return false;
34}
35
36Status ChromeImpl::GetWebViewIds(std::list<std::string>* web_view_ids) {
37  WebViewsInfo views_info;
38  Status status = devtools_http_client_->GetWebViewsInfo(&views_info);
39  if (status.IsError())
40    return status;
41
42  // Check if some web views are closed.
43  WebViewList::iterator it = web_views_.begin();
44  while (it != web_views_.end()) {
45    if (!views_info.GetForId((*it)->GetId())) {
46      it = web_views_.erase(it);
47    } else {
48      ++it;
49    }
50  }
51
52  // Check for newly-opened web views.
53  for (size_t i = 0; i < views_info.GetSize(); ++i) {
54    const WebViewInfo& view = views_info.Get(i);
55    if (view.type != WebViewInfo::kPage && view.type != WebViewInfo::kApp)
56      continue;
57
58    // Workaround to ignore generated background pages that are
59    // being returned as active windows for some builds of Chrome.
60    // TODO(bustamante): Once Chrome builds < 1755 are no longer
61    //   supported this check can be removed.
62    int kBuildNumber = devtools_http_client_->browser_info()->build_no;
63    if (kBuildNumber < 1755 && view.type == WebViewInfo::kApp &&
64        view.url.find("_generated_background") != std::string::npos)
65      continue;
66
67    bool found = false;
68    for (WebViewList::const_iterator web_view_iter = web_views_.begin();
69         web_view_iter != web_views_.end(); ++web_view_iter) {
70      if ((*web_view_iter)->GetId() == view.id) {
71        found = true;
72        break;
73      }
74    }
75    if (!found) {
76      scoped_ptr<DevToolsClient> client(
77          devtools_http_client_->CreateClient(view.id));
78      for (ScopedVector<DevToolsEventListener>::const_iterator listener =
79               devtools_event_listeners_.begin();
80           listener != devtools_event_listeners_.end(); ++listener) {
81        client->AddListener(*listener);
82        // OnConnected will fire when DevToolsClient connects later.
83      }
84      web_views_.push_back(make_linked_ptr(new WebViewImpl(
85          view.id,
86          devtools_http_client_->browser_info(),
87          client.Pass(),
88          devtools_http_client_->device_metrics())));
89    }
90  }
91
92  std::list<std::string> web_view_ids_tmp;
93  for (WebViewList::const_iterator web_view_iter = web_views_.begin();
94       web_view_iter != web_views_.end(); ++web_view_iter) {
95    web_view_ids_tmp.push_back((*web_view_iter)->GetId());
96  }
97  web_view_ids->swap(web_view_ids_tmp);
98  return Status(kOk);
99}
100
101Status ChromeImpl::GetWebViewById(const std::string& id, WebView** web_view) {
102  for (WebViewList::iterator it = web_views_.begin();
103       it != web_views_.end(); ++it) {
104    if ((*it)->GetId() == id) {
105      *web_view = (*it).get();
106      return Status(kOk);
107    }
108  }
109  return Status(kUnknownError, "web view not found");
110}
111
112Status ChromeImpl::CloseWebView(const std::string& id) {
113  Status status = devtools_http_client_->CloseWebView(id);
114  if (status.IsError())
115    return status;
116  for (WebViewList::iterator iter = web_views_.begin();
117       iter != web_views_.end(); ++iter) {
118    if ((*iter)->GetId() == id) {
119      web_views_.erase(iter);
120      break;
121    }
122  }
123  return Status(kOk);
124}
125
126Status ChromeImpl::ActivateWebView(const std::string& id) {
127  return devtools_http_client_->ActivateWebView(id);
128}
129
130bool ChromeImpl::IsMobileEmulationEnabled() const {
131  return false;
132}
133
134Status ChromeImpl::Quit() {
135  Status status = QuitImpl();
136  if (status.IsOk())
137    quit_ = true;
138  return status;
139}
140
141ChromeImpl::ChromeImpl(
142    scoped_ptr<DevToolsHttpClient> http_client,
143    scoped_ptr<DevToolsClient> websocket_client,
144    ScopedVector<DevToolsEventListener>& devtools_event_listeners,
145    scoped_ptr<PortReservation> port_reservation)
146    : quit_(false),
147      devtools_http_client_(http_client.Pass()),
148      devtools_websocket_client_(websocket_client.Pass()),
149      port_reservation_(port_reservation.Pass()) {
150  devtools_event_listeners_.swap(devtools_event_listeners);
151}
152