| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "android_webview/browser/aw_devtools_delegate.h" | 5 #include "android_webview/browser/aw_devtools_delegate.h" |
| 6 | 6 |
| 7 #include "android_webview/browser/browser_view_renderer.h" |
| 7 #include "base/bind.h" | 8 #include "base/bind.h" |
| 9 #include "base/json/json_writer.h" |
| 8 #include "base/stringprintf.h" | 10 #include "base/stringprintf.h" |
| 11 #include "base/values.h" |
| 9 #include "content/public/browser/android/devtools_auth.h" | 12 #include "content/public/browser/android/devtools_auth.h" |
| 10 #include "content/public/browser/devtools_http_handler.h" | 13 #include "content/public/browser/devtools_http_handler.h" |
| 11 #include "content/public/browser/web_contents.h" | 14 #include "content/public/browser/web_contents.h" |
| 12 #include "content/public/common/url_constants.h" | 15 #include "content/public/common/url_constants.h" |
| 13 #include "net/base/unix_domain_socket_posix.h" | 16 #include "net/base/unix_domain_socket_posix.h" |
| 14 #include "ui/base/resource/resource_bundle.h" | 17 #include "ui/base/resource/resource_bundle.h" |
| 15 | 18 |
| 16 namespace { | 19 namespace { |
| 17 const char kSocketNameFormat[] = "webview_devtools_remote_%d"; | 20 const char kSocketNameFormat[] = "webview_devtools_remote_%d"; |
| 18 } | 21 } |
| 19 | 22 |
| 20 namespace android_webview { | 23 namespace android_webview { |
| 21 | 24 |
| 22 AwDevToolsDelegate::AwDevToolsDelegate(content::BrowserContext* browser_context) | 25 AwDevToolsDelegate::AwDevToolsDelegate(content::BrowserContext* browser_context) |
| 23 : browser_context_(browser_context) { | 26 : browser_context_(browser_context) { |
| 24 devtools_http_handler_ = content::DevToolsHttpHandler::Start( | 27 devtools_http_handler_ = content::DevToolsHttpHandler::Start( |
| 25 new net::UnixDomainSocketWithAbstractNamespaceFactory( | 28 new net::UnixDomainSocketWithAbstractNamespaceFactory( |
| 26 StringPrintf(kSocketNameFormat, getpid()), | 29 StringPrintf(kSocketNameFormat, getpid()), |
| 27 base::Bind(&content::CanUserConnectToDevTools)), | 30 base::Bind(&content::CanUserConnectToDevTools)), |
| 28 "", | 31 "", |
| 29 this); | 32 this); |
| 30 } | 33 } |
| 31 | 34 |
| 32 AwDevToolsDelegate::~AwDevToolsDelegate() { | 35 AwDevToolsDelegate::~AwDevToolsDelegate() { |
| 33 } | 36 } |
| 34 | 37 |
| 35 void AwDevToolsDelegate::Stop() { | 38 void AwDevToolsDelegate::Stop() { |
| 36 // The HTTP handler will delete our instance. | |
| 37 devtools_http_handler_->Stop(); | 39 devtools_http_handler_->Stop(); |
| 40 // WARNING: |this| has now been deleted by the method above. |
| 38 } | 41 } |
| 39 | 42 |
| 40 std::string AwDevToolsDelegate::GetDiscoveryPageHTML() { | 43 std::string AwDevToolsDelegate::GetDiscoveryPageHTML() { |
| 41 // This is a temporary way of providing the list of inspectable WebViews. | 44 // This is a temporary way of providing the list of inspectable WebViews. |
| 42 // Since WebView doesn't have its own resources now, it doesn't seem | 45 // Since WebView doesn't have its own resources now, it doesn't seem |
| 43 // reasonable to create a dedicated .pak file just for this temporary page. | 46 // reasonable to create a dedicated .pak file just for this temporary page. |
| 44 const char html[] = | 47 const char html[] = |
| 45 "<html>" | 48 "<html>" |
| 46 "<head>" | 49 "<head>" |
| 47 "<title>WebView remote debugging</title>" | 50 "<title>WebView remote debugging</title>" |
| 48 "<style>" | 51 "<style>" |
| 49 "</style>" | 52 "</style>" |
| 50 "<script>" | 53 "<script>" |
| 51 "function onLoad() {" | 54 "function onLoad() {" |
| 52 " var tabs_list_request = new XMLHttpRequest();" | 55 " var tabs_list_request = new XMLHttpRequest();" |
| 53 " tabs_list_request.open(" | 56 " tabs_list_request.open(" |
| 54 "\"GET\", \"/json/list?t=\" + new Date().getTime(), true);" | 57 " 'GET', '/json/list?t=' + new Date().getTime(), true);" |
| 55 " tabs_list_request.onreadystatechange = onReady;" | 58 " tabs_list_request.onreadystatechange = onReady;" |
| 56 " tabs_list_request.send();" | 59 " tabs_list_request.send();" |
| 57 "}" | 60 "}" |
| 61 "function viewsComparator(v1, v2) {" |
| 62 " if (v1.attached != v2.attached) {" |
| 63 " return v1.attached ? -1 : 1;" |
| 64 " } else if (v1.visible != v2.visible) {" |
| 65 " return v1.visible ? -1 : 1;" |
| 66 " } else if (v1.empty != v2.empty) {" |
| 67 " return v1.empty ? 1 : -1;" |
| 68 " } else if (v1.screenX != v2.screenX) {" |
| 69 " return v1.screenX - v2.screenX;" |
| 70 " } else if (v1.screenY != v2.screenY) {" |
| 71 " return v1.screenY - v2.screenY;" |
| 72 " }" |
| 73 " return 0;" |
| 74 "}" |
| 75 "function processItem(item) {" |
| 76 " var result = JSON.parse(item.description);" |
| 77 " result.debuggable = !!item.devtoolsFrontendUrl;" |
| 78 " result.debugUrl = item.devtoolsFrontendUrl;" |
| 79 " result.title = item.title;" |
| 80 " return result;" |
| 81 "}" |
| 58 "function onReady() {" | 82 "function onReady() {" |
| 59 " if(this.readyState == 4 && this.status == 200) {" | 83 " if(this.readyState == 4 && this.status == 200) {" |
| 60 " if(this.response != null)" | 84 " if(this.response != null)" |
| 61 " var responseJSON = JSON.parse(this.response);" | 85 " var responseJSON = JSON.parse(this.response);" |
| 86 " var items = [];" |
| 62 " for (var i = 0; i < responseJSON.length; ++i)" | 87 " for (var i = 0; i < responseJSON.length; ++i)" |
| 63 " appendItem(responseJSON[i]);" | 88 " items.push(processItem(responseJSON[i]));" |
| 89 " items.sort(viewsComparator);" |
| 90 " for (var i = 0; i < items.length; ++i)" |
| 91 " displayView(items[i]);" |
| 64 " }" | 92 " }" |
| 65 "}" | 93 "}" |
| 66 "function appendItem(item_object) {" | 94 "function addColumn(row, text) {" |
| 95 " var column = document.createElement('td');" |
| 96 " column.innerText = text;" |
| 97 " row.appendChild(column);" |
| 98 "}" |
| 99 "function cutTextIfNeeded(text, maxLen) {" |
| 100 " return text.length <= maxLen ?" |
| 101 " text : text.substr(0, maxLen) + '\u2026';" |
| 102 "}" |
| 103 "function displayView(item) {" |
| 104 " var row = document.createElement('tr');" |
| 105 " var column = document.createElement('td');" |
| 67 " var frontend_ref;" | 106 " var frontend_ref;" |
| 68 " if (item_object.devtoolsFrontendUrl) {" | 107 " if (item.debuggable) {" |
| 69 " frontend_ref = document.createElement(\"a\");" | 108 " frontend_ref = document.createElement('a');" |
| 70 " frontend_ref.href = item_object.devtoolsFrontendUrl;" | 109 " frontend_ref.href = item.debugUrl;" |
| 71 " frontend_ref.title = item_object.title;" | 110 " frontend_ref.title = item.title;" |
| 111 " column.appendChild(frontend_ref);" |
| 72 " } else {" | 112 " } else {" |
| 73 " frontend_ref = document.createElement(\"div\");" | 113 " frontend_ref = column;" |
| 74 " frontend_ref.title = " | |
| 75 "\"The view already has active debugging session\";" | |
| 76 " }" | 114 " }" |
| 77 " var text = document.createElement(\"div\");" | 115 " var text = document.createElement('span');" |
| 78 " if (item_object.title)" | 116 " if (item.title) {" |
| 79 " text.innerText = item_object.title;" | 117 " text.innerText = cutTextIfNeeded(item.title, 64);" |
| 80 " else" | 118 " } else {" |
| 81 " text.innerText = \"(untitled tab)\";" | 119 " text.innerText = '(untitled)';" |
| 82 " text.style.cssText = " | 120 " }" |
| 83 "\"background-image:url(\" + item_object.faviconUrl + \")\";" | |
| 84 " frontend_ref.appendChild(text);" | 121 " frontend_ref.appendChild(text);" |
| 85 " var item = document.createElement(\"p\");" | 122 " row.appendChild(column);" |
| 86 " item.appendChild(frontend_ref);" | 123 " addColumn(row, item.attached ? 'Y' : 'N');" |
| 87 " document.getElementById(\"items\").appendChild(item);" | 124 " addColumn(row, item.visible ? 'Y' : 'N');" |
| 125 " addColumn(row, item.empty ? 'Y' : 'N');" |
| 126 " addColumn(row, item.screenX + ', ' + item.screenY);" |
| 127 " addColumn(row," |
| 128 " !item.empty ? (item.width + '\u00d7' + item.height) : '');" |
| 129 " document.getElementById('items').appendChild(row);" |
| 88 "}" | 130 "}" |
| 89 "</script>" | 131 "</script>" |
| 90 "</head>" | 132 "</head>" |
| 91 "<body onload='onLoad()'>" | 133 "<body onload='onLoad()'>" |
| 92 " <div id='caption'>Inspectable WebViews</div>" | 134 " <div id='caption'>Inspectable WebViews</div>" |
| 93 " <div id='items'></div>" | 135 " <table>" |
| 136 " <tr><th>Title</th><th>Attached</th><th>Visible</th><th>Empty</th>" |
| 137 "<th>Position</th><th>Size</th></tr>" |
| 138 " <tbody id='items'></tbody>" |
| 139 " </table>" |
| 94 "</body>" | 140 "</body>" |
| 95 "</html>"; | 141 "</html>"; |
| 96 return html; | 142 return html; |
| 97 } | 143 } |
| 98 | 144 |
| 99 bool AwDevToolsDelegate::BundlesFrontendResources() { | 145 bool AwDevToolsDelegate::BundlesFrontendResources() { |
| 100 return true; | 146 return true; |
| 101 } | 147 } |
| 102 | 148 |
| 103 base::FilePath AwDevToolsDelegate::GetDebugFrontendDir() { | 149 base::FilePath AwDevToolsDelegate::GetDebugFrontendDir() { |
| 104 return base::FilePath(); | 150 return base::FilePath(); |
| 105 } | 151 } |
| 106 | 152 |
| 107 std::string AwDevToolsDelegate::GetPageThumbnailData(const GURL& url) { | 153 std::string AwDevToolsDelegate::GetPageThumbnailData(const GURL& url) { |
| 108 return ""; | 154 return ""; |
| 109 } | 155 } |
| 110 | 156 |
| 111 content::RenderViewHost* AwDevToolsDelegate::CreateNewTarget() { | 157 content::RenderViewHost* AwDevToolsDelegate::CreateNewTarget() { |
| 112 return NULL; | 158 return NULL; |
| 113 } | 159 } |
| 114 | 160 |
| 115 content::DevToolsHttpHandlerDelegate::TargetType | 161 content::DevToolsHttpHandlerDelegate::TargetType |
| 116 AwDevToolsDelegate::GetTargetType(content::RenderViewHost*) { | 162 AwDevToolsDelegate::GetTargetType(content::RenderViewHost*) { |
| 117 return kTargetTypeTab; | 163 return kTargetTypeTab; |
| 118 } | 164 } |
| 119 | 165 |
| 166 std::string AwDevToolsDelegate::GetViewDescription( |
| 167 content::RenderViewHost* rvh) { |
| 168 content::WebContents* web_contents = |
| 169 content::WebContents::FromRenderViewHost(rvh); |
| 170 if (!web_contents) return ""; |
| 171 BrowserViewRenderer* bvr = BrowserViewRenderer::FromWebContents(web_contents); |
| 172 if (!bvr) return ""; |
| 173 base::DictionaryValue description; |
| 174 description.SetBoolean("attached", bvr->isAttachedToViewHierarchy()); |
| 175 description.SetBoolean("visible", bvr->isViewVisible()); |
| 176 gfx::Rect screen_rect = bvr->getScreenRect(); |
| 177 description.SetInteger("screenX", screen_rect.x()); |
| 178 description.SetInteger("screenY", screen_rect.y()); |
| 179 description.SetBoolean("empty", screen_rect.size().IsEmpty()); |
| 180 if (!screen_rect.size().IsEmpty()) { |
| 181 description.SetInteger("width", screen_rect.width()); |
| 182 description.SetInteger("height", screen_rect.height()); |
| 183 } |
| 184 std::string json; |
| 185 base::JSONWriter::Write(&description, &json); |
| 186 return json; |
| 187 } |
| 188 |
| 120 } // namespace android_webview | 189 } // namespace android_webview |
| OLD | NEW |