| 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());
|
| +}
|
|
|