Index: chrome/browser/ui/webui/devtools_ui.cc |
diff --git a/chrome/browser/ui/webui/devtools_ui.cc b/chrome/browser/ui/webui/devtools_ui.cc |
index c9fb2d33608a78e10b0ea8260b1bea262accf344..423b4946704a27e011f993edeff17408e9b1e3ba 100644 |
--- a/chrome/browser/ui/webui/devtools_ui.cc |
+++ b/chrome/browser/ui/webui/devtools_ui.cc |
@@ -6,14 +6,21 @@ |
#include <string> |
+#include "base/command_line.h" |
#include "base/memory/ref_counted_memory.h" |
#include "base/memory/scoped_ptr.h" |
#include "base/strings/string_util.h" |
#include "base/strings/stringprintf.h" |
+#include "chrome/browser/devtools/device/devtools_android_bridge.h" |
+#include "chrome/browser/devtools/devtools_target_impl.h" |
#include "chrome/browser/profiles/profile.h" |
+#include "chrome/common/chrome_switches.h" |
#include "chrome/common/url_constants.h" |
#include "content/public/browser/browser_thread.h" |
#include "content/public/browser/devtools_http_handler.h" |
+#include "content/public/browser/navigation_controller.h" |
+#include "content/public/browser/navigation_details.h" |
+#include "content/public/browser/navigation_entry.h" |
#include "content/public/browser/url_data_source.h" |
#include "content/public/browser/web_contents.h" |
#include "content/public/browser/web_ui.h" |
@@ -47,6 +54,12 @@ const char kFallbackFrontendURL[] = |
"data:text/plain,Cannot load DevTools frontend from an untrusted origin"; |
#endif // defined(DEBUG_DEVTOOLS) |
+const char kRemoteOpenPrefix[] = "remote/open"; |
+ |
+#if defined(DEBUG_DEVTOOLS) |
+const char kLocalSerial[] = "local"; |
+#endif // defined(DEBUG_DEVTOOLS) |
+ |
// FetchRequest --------------------------------------------------------------- |
class FetchRequest : public net::URLFetcherDelegate { |
@@ -105,14 +118,14 @@ std::string GetMimeTypeForPath(const std::string& path) { |
} else if (EndsWith(filename, ".manifest", false)) { |
return "text/cache-manifest"; |
} |
- NOTREACHED(); |
- return "text/plain"; |
+ return "text/html"; |
} |
// An URLDataSource implementation that handles chrome-devtools://devtools/ |
// requests. Three types of requests could be handled based on the URL path: |
// 1. /bundled/: bundled DevTools frontend is served. |
-// 2. /remote/: Remote DevTools frontend is served from App Engine. |
+// 2. /remote/: remote DevTools frontend is served from App Engine. |
+// 3. /remote/open/: query is URL which is opened on remote device. |
class DevToolsDataSource : public content::URLDataSource { |
public: |
explicit DevToolsDataSource(net::URLRequestContextGetter* request_context); |
@@ -175,6 +188,18 @@ void DevToolsDataSource::StartDataRequest( |
return; |
} |
+ // Serve static response while connecting to the remote device. |
+ if (StartsWithASCII(path, kRemoteOpenPrefix, false)) { |
+ if (!CommandLine::ForCurrentProcess()->HasSwitch( |
+ switches::kEnableDevToolsExperiments)) { |
+ callback.Run(NULL); |
+ return; |
+ } |
+ std::string response = "Connecting to the device..."; |
+ callback.Run(base::RefCountedString::TakeString(&response)); |
+ return; |
+ } |
+ |
// Serve request from remote location. |
std::string remote_path_prefix(chrome::kChromeUIDevToolsRemotePath); |
remote_path_prefix += "/"; |
@@ -228,6 +253,86 @@ void DevToolsDataSource::StartRemoteDataRequest( |
new FetchRequest(request_context_, url, callback); |
} |
+// OpenRemotePageRequest ------------------------------------------------------ |
+ |
+class OpenRemotePageRequest : public DevToolsAndroidBridge::DeviceListListener { |
+ public: |
+ OpenRemotePageRequest( |
+ Profile* profile, |
+ const std::string url, |
+ const DevToolsAndroidBridge::RemotePageCallback& callback); |
+ virtual ~OpenRemotePageRequest() {} |
+ |
+ private: |
+ // DevToolsAndroidBridge::Listener overrides. |
+ virtual void DeviceListChanged( |
+ const DevToolsAndroidBridge::RemoteDevices& devices) OVERRIDE; |
+ |
+ bool OpenInBrowser(DevToolsAndroidBridge::RemoteBrowser* browser); |
+ void RemotePageOpened(DevToolsAndroidBridge::RemotePage* page); |
+ |
+ std::string url_; |
+ DevToolsAndroidBridge::RemotePageCallback callback_; |
+ bool opening_; |
+ scoped_refptr<DevToolsAndroidBridge> android_bridge_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(OpenRemotePageRequest); |
+}; |
+ |
+OpenRemotePageRequest::OpenRemotePageRequest( |
+ Profile* profile, |
+ const std::string url, |
+ const DevToolsAndroidBridge::RemotePageCallback& callback) |
+ : url_(url), |
+ callback_(callback), |
+ opening_(false), |
+ android_bridge_( |
+ DevToolsAndroidBridge::Factory::GetForProfile(profile)) { |
+ android_bridge_->AddDeviceListListener(this); |
+} |
+ |
+void OpenRemotePageRequest::DeviceListChanged( |
+ const DevToolsAndroidBridge::RemoteDevices& devices) { |
+ if (opening_) |
+ return; |
+ |
+ for (DevToolsAndroidBridge::RemoteDevices::const_iterator dit = |
+ devices.begin(); dit != devices.end(); ++dit) { |
+ DevToolsAndroidBridge::RemoteDevice* device = dit->get(); |
+ if (!device->is_connected()) |
+ continue; |
+ |
+ DevToolsAndroidBridge::RemoteBrowsers& browsers = device->browsers(); |
+ for (DevToolsAndroidBridge::RemoteBrowsers::iterator bit = |
+ browsers.begin(); bit != browsers.end(); ++bit) { |
+ if (OpenInBrowser(bit->get())) { |
+ opening_ = true; |
+ return; |
+ } |
+ } |
+ } |
+} |
+ |
+bool OpenRemotePageRequest::OpenInBrowser( |
+ DevToolsAndroidBridge::RemoteBrowser* browser) { |
+ if (!browser->IsChrome()) |
+ return false; |
+#if defined(DEBUG_DEVTOOLS) |
+ if (browser->serial() == kLocalSerial) |
+ return false; |
+#endif // defined(DEBUG_DEVTOOLS) |
+ browser->Open(url_, base::Bind(&OpenRemotePageRequest::RemotePageOpened, |
+ base::Unretained(this))); |
+ return true; |
+} |
+ |
+void OpenRemotePageRequest::RemotePageOpened( |
+ DevToolsAndroidBridge::RemotePage* page) { |
+ callback_.Run(page); |
+ android_bridge_->RemoveDeviceListListener(this); |
+ delete this; |
+} |
+ |
} // namespace |
// DevToolsUI ----------------------------------------------------------------- |
@@ -246,10 +351,65 @@ GURL DevToolsUI::GetProxyURL(const std::string& frontend_url) { |
DevToolsUI::DevToolsUI(content::WebUI* web_ui) |
: WebUIController(web_ui), |
- bindings_(web_ui->GetWebContents()) { |
+ content::WebContentsObserver(web_ui->GetWebContents()), |
+ bindings_(web_ui->GetWebContents()), |
+ weak_factory_(this) { |
web_ui->SetBindings(0); |
Profile* profile = Profile::FromWebUI(web_ui); |
content::URLDataSource::Add( |
profile, |
new DevToolsDataSource(profile->GetRequestContext())); |
} |
+ |
+DevToolsUI::~DevToolsUI() { |
+} |
+ |
+void DevToolsUI::NavigationEntryCommitted( |
+ const content::LoadCommittedDetails& load_details) { |
+ content::NavigationEntry* entry = load_details.entry; |
+ if (!CommandLine::ForCurrentProcess()->HasSwitch( |
+ switches::kEnableDevToolsExperiments)) { |
+ return; |
+ } |
+ |
+ if (entry->GetVirtualURL() == remote_frontend_loading_url_) { |
+ remote_frontend_loading_url_ = GURL(); |
+ return; |
+ } |
+ |
+ std::string path = entry->GetVirtualURL().path().substr(1); |
+ if (!StartsWithASCII(path, kRemoteOpenPrefix, false)) |
+ return; |
+ |
+ bindings_.Detach(); |
+ remote_page_opening_url_ = entry->GetVirtualURL(); |
+ new OpenRemotePageRequest(Profile::FromWebUI(web_ui()), |
+ entry->GetVirtualURL().query(), |
+ base::Bind(&DevToolsUI::RemotePageOpened, |
+ weak_factory_.GetWeakPtr(), |
+ entry->GetVirtualURL())); |
+} |
+ |
+void DevToolsUI::RemotePageOpened( |
+ const GURL& virtual_url, DevToolsAndroidBridge::RemotePage* page) { |
+ // Already navigated away while connecting to remote device. |
+ if (remote_page_opening_url_ != virtual_url) |
+ return; |
+ |
+ scoped_ptr<DevToolsAndroidBridge::RemotePage> my_page(page); |
+ remote_page_opening_url_ = GURL(); |
+ |
+ Profile* profile = Profile::FromWebUI(web_ui()); |
+ GURL url = DevToolsUIBindings::ApplyThemeToURL(profile, |
+ DevToolsUI::GetProxyURL(page->GetFrontendURL())); |
+ |
+ content::NavigationController& navigation_controller = |
+ web_ui()->GetWebContents()->GetController(); |
+ content::NavigationController::LoadURLParams params(url); |
+ params.should_replace_current_entry = true; |
+ remote_frontend_loading_url_ = virtual_url; |
+ navigation_controller.LoadURLWithParams(params); |
+ navigation_controller.GetPendingEntry()->SetVirtualURL(virtual_url); |
+ |
+ bindings_.AttachTo(page->GetTarget()->GetAgentHost()); |
+} |