[Android WebView] Disable fallback ticks when paused or window invisible
[chromium-blink-merge.git] / android_webview / browser / aw_devtools_delegate.cc
blob25f2b7ace7f03f922737a353005a68bdf0938fdb
1 // Copyright 2013 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.
5 #include "android_webview/browser/aw_devtools_delegate.h"
7 #include "android_webview/browser/in_process_view_renderer.h"
8 #include "base/bind.h"
9 #include "base/json/json_writer.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/values.h"
12 #include "content/public/browser/android/devtools_auth.h"
13 #include "content/public/browser/devtools_http_handler.h"
14 #include "content/public/browser/web_contents.h"
15 #include "content/public/common/url_constants.h"
16 #include "net/socket/unix_domain_socket_posix.h"
17 #include "ui/base/resource/resource_bundle.h"
18 #include "webkit/common/user_agent/user_agent_util.h"
20 namespace {
21 const char kFrontEndURL[] =
22 "http://chrome-devtools-frontend.appspot.com/serve_rev/%s/devtools.html";
23 const char kSocketNameFormat[] = "webview_devtools_remote_%d";
26 namespace android_webview {
28 AwDevToolsDelegate::AwDevToolsDelegate(content::BrowserContext* browser_context)
29 : browser_context_(browser_context) {
30 devtools_http_handler_ = content::DevToolsHttpHandler::Start(
31 new net::UnixDomainSocketWithAbstractNamespaceFactory(
32 base::StringPrintf(kSocketNameFormat, getpid()),
33 "",
34 base::Bind(&content::CanUserConnectToDevTools)),
35 base::StringPrintf(kFrontEndURL,
36 webkit_glue::GetWebKitRevision().c_str()),
37 this);
40 AwDevToolsDelegate::~AwDevToolsDelegate() {
43 void AwDevToolsDelegate::Stop() {
44 devtools_http_handler_->Stop();
45 // WARNING: |this| has now been deleted by the method above.
48 std::string AwDevToolsDelegate::GetDiscoveryPageHTML() {
49 // This is a temporary way of providing the list of inspectable WebViews.
50 // Since WebView doesn't have its own resources now, it doesn't seem
51 // reasonable to create a dedicated .pak file just for this temporary page.
52 const char html[] =
53 "<html>"
54 "<head>"
55 "<title>WebView remote debugging</title>"
56 "<style>"
57 "</style>"
58 "<script>"
59 "function onLoad() {"
60 " var tabs_list_request = new XMLHttpRequest();"
61 " tabs_list_request.open("
62 " 'GET', '/json/list?t=' + new Date().getTime(), true);"
63 " tabs_list_request.onreadystatechange = onReady;"
64 " tabs_list_request.send();"
65 "}"
66 "function processItem(item) {"
67 " var result = JSON.parse(item.description);"
68 " result.debuggable = !!item.devtoolsFrontendUrl;"
69 " result.debugUrl = item.devtoolsFrontendUrl;"
70 " result.title = item.title;"
71 " return result;"
72 "}"
73 "function onReady() {"
74 " if(this.readyState == 4 && this.status == 200) {"
75 " if(this.response != null)"
76 " var responseJSON = JSON.parse(this.response);"
77 " var items = [];"
78 " for (var i = 0; i < responseJSON.length; ++i)"
79 " items.push(processItem(responseJSON[i]));"
80 " clear();"
81 " for (var i = 0; i < items.length; ++i)"
82 " displayView(items[i]);"
83 " filter();"
84 " }"
85 "}"
86 "function addColumn(row, text) {"
87 " var column = document.createElement('td');"
88 " column.innerText = text;"
89 " row.appendChild(column);"
90 "}"
91 "function cutTextIfNeeded(text, maxLen) {"
92 " return text.length <= maxLen ?"
93 " text : text.substr(0, maxLen) + '\u2026';"
94 "}"
95 "function displayView(item) {"
96 " var row = document.createElement('tr');"
97 " var column = document.createElement('td');"
98 " var frontend_ref;"
99 " if (item.debuggable) {"
100 " frontend_ref = document.createElement('a');"
101 " frontend_ref.href = item.debugUrl;"
102 " frontend_ref.title = item.title;"
103 " frontend_ref.target = '_blank';"
104 " column.appendChild(frontend_ref);"
105 " } else {"
106 " frontend_ref = column;"
107 " }"
108 " var text = document.createElement('span');"
109 " if (item.title) {"
110 " text.innerText = cutTextIfNeeded(item.title, 64);"
111 " } else {"
112 " text.innerText = '(untitled)';"
113 " }"
114 " frontend_ref.appendChild(text);"
115 " var bits = 0;"
116 " var attached = item.attached ? (bits |= 1, 'Y') : 'N';"
117 " var visible = item.visible ? (bits |= 2, 'Y') : 'N';"
118 " var empty = item.empty ? 'Y' : (bits |= 4, 'N');"
119 " row.setAttribute('class', bits);"
120 " row.appendChild(column);"
121 " addColumn(row, attached);"
122 " addColumn(row, visible);"
123 " addColumn(row, empty);"
124 " addColumn(row, item.screenX + ', ' + item.screenY);"
125 " addColumn(row,"
126 " !item.empty ? (item.width + '\u00d7' + item.height) : '');"
127 " document.getElementById('items').appendChild(row);"
129 "function filter() {"
130 " var show_attached = document.getElementById('show_attached').checked;"
131 " var show_visible = document.getElementById('show_visible').checked;"
132 " var show_nonempty = document.getElementById('show_nonempty').checked;"
133 " var items = document.getElementById('items').childNodes;"
134 " for (var i = 0; i < items.length; i++) {"
135 " if (items[i].nodeName == 'TR') {"
136 " var mask = parseInt(items[i].getAttribute('class'));"
137 " var show = true;"
138 " if (show_attached) show &= ((mask & 1) != 0);"
139 " if (show_visible) show &= ((mask & 2) != 0);"
140 " if (show_nonempty) show &= ((mask & 4) != 0);"
141 " if (show) {"
142 " items[i].style.display = 'table-row';"
143 " } else {"
144 " items[i].style.display = 'none';"
145 " }"
146 " }"
147 " }"
149 "var refreshInterval = 0;"
150 "function toggleRefresh() {"
151 " clearInterval(refreshInterval);"
152 " var enabled = document.getElementById('refresh').checked;"
153 " if (enabled) {"
154 " var time = document.getElementById('refresh_time').value * 1000;"
155 " refreshInterval = setInterval(onLoad, time);"
156 " }"
158 "function clear() {"
159 " var items = document.getElementById('items');"
160 " for (var i = 0; i < items.childNodes.length; i++) {"
161 " items.removeChild(items.childNodes[i]);"
162 " }"
164 "</script>"
165 "</head>"
166 "<body onload='onLoad()'>"
167 " <div id='caption'>Inspectable WebViews</div>"
168 " <div><p>Only show:</p>"
169 " <form>"
170 " <input type='checkbox' id='show_attached' onclick='filter()'>"
171 " Attached<br/>"
172 " <input type='checkbox' id='show_visible' onclick='filter()'>"
173 " Visible<br/>"
174 " <input type='checkbox' id='show_nonempty' onclick='filter()'>"
175 " Non-empty<br/>"
176 " <input type='checkbox' id='refresh' onclick='toggleRefresh()'>"
177 " Auto refresh every "
178 " <input type='number' id='refresh_time' value='2' min='1' max='99'"
179 " onchange='toggleRefresh();' /> seconds<br/>"
180 " </form>"
181 " </div>"
182 " <table>"
183 " <tr><th style='width:200px; text-align:left;'>Title</th>"
184 " <th>Attached</th><th>Visible</th><th>Empty</th>"
185 " <th style='width:100px; text-align:left;'>Position</th>"
186 " <th style='width:100px; text-align:left;'>Size</th>"
187 " </tr>"
188 " <tbody id='items'></tbody>"
189 " </table>"
190 "</body>"
191 "</html>";
192 return html;
195 bool AwDevToolsDelegate::BundlesFrontendResources() {
196 return false;
199 base::FilePath AwDevToolsDelegate::GetDebugFrontendDir() {
200 return base::FilePath();
203 std::string AwDevToolsDelegate::GetPageThumbnailData(const GURL& url) {
204 return "";
207 content::RenderViewHost* AwDevToolsDelegate::CreateNewTarget() {
208 return NULL;
211 content::DevToolsHttpHandlerDelegate::TargetType
212 AwDevToolsDelegate::GetTargetType(content::RenderViewHost*) {
213 return kTargetTypeTab;
216 std::string AwDevToolsDelegate::GetViewDescription(
217 content::RenderViewHost* rvh) {
218 content::WebContents* web_contents =
219 content::WebContents::FromRenderViewHost(rvh);
220 if (!web_contents) return "";
222 BrowserViewRenderer* bvr
223 = InProcessViewRenderer::FromWebContents(web_contents);
224 if (!bvr) return "";
225 base::DictionaryValue description;
226 description.SetBoolean("attached", bvr->IsAttachedToWindow());
227 description.SetBoolean("visible", bvr->IsVisible());
228 gfx::Rect screen_rect = bvr->GetScreenRect();
229 description.SetInteger("screenX", screen_rect.x());
230 description.SetInteger("screenY", screen_rect.y());
231 description.SetBoolean("empty", screen_rect.size().IsEmpty());
232 if (!screen_rect.size().IsEmpty()) {
233 description.SetInteger("width", screen_rect.width());
234 description.SetInteger("height", screen_rect.height());
236 std::string json;
237 base::JSONWriter::Write(&description, &json);
238 return json;
241 scoped_refptr<net::StreamListenSocket>
242 AwDevToolsDelegate::CreateSocketForTethering(
243 net::StreamListenSocket::Delegate* delegate,
244 std::string* name) {
245 return NULL;
248 } // namespace android_webview