| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 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/browser/devtools/device/webrtc/devtools_bridge_client.h" | |
| 6 | |
| 7 #include <stddef.h> | |
| 8 | |
| 9 #include "base/callback.h" | |
| 10 #include "chrome/browser/chrome_notification_types.h" | |
| 11 #include "chrome/browser/local_discovery/gcd_api_flow.h" | |
| 12 #include "chrome/common/url_constants.h" | |
| 13 #include "components/signin/core/browser/profile_identity_provider.h" | |
| 14 #include "content/public/browser/notification_observer.h" | |
| 15 #include "content/public/browser/notification_registrar.h" | |
| 16 #include "content/public/browser/notification_source.h" | |
| 17 #include "content/public/browser/web_contents.h" | |
| 18 #include "content/public/browser/web_contents_observer.h" | |
| 19 #include "content/public/browser/web_contents_user_data.h" | |
| 20 #include "ui/base/page_transition_types.h" | |
| 21 | |
| 22 using content::BrowserThread; | |
| 23 using content::WebContents; | |
| 24 | |
| 25 namespace { | |
| 26 | |
| 27 const char kBackgroundWorkerURL[] = | |
| 28 "chrome://webrtc-device-provider/background_worker.html"; | |
| 29 const char kSerial[] = "webrtc"; | |
| 30 const char kPseudoDeviceName[] = "Remote browsers"; | |
| 31 const char kDeviceIdPrefix[] = "device-id:"; | |
| 32 | |
| 33 class BackgroundWorkerUserData | |
| 34 : public content::WebContentsUserData<BackgroundWorkerUserData> { | |
| 35 public: | |
| 36 DevToolsBridgeClient* client() const { return client_; } | |
| 37 void SetClient(DevToolsBridgeClient* client) { client_ = client; } | |
| 38 | |
| 39 private: | |
| 40 friend WebContentsUserData<BackgroundWorkerUserData>; | |
| 41 | |
| 42 explicit BackgroundWorkerUserData(WebContents* contents) : client_(nullptr) {} | |
| 43 | |
| 44 DevToolsBridgeClient* client_; | |
| 45 }; | |
| 46 | |
| 47 } // namespace | |
| 48 | |
| 49 DEFINE_WEB_CONTENTS_USER_DATA_KEY(BackgroundWorkerUserData); | |
| 50 | |
| 51 // DevToolsBridgeClient -------------------------------------------------------- | |
| 52 | |
| 53 // static | |
| 54 base::WeakPtr<DevToolsBridgeClient> DevToolsBridgeClient::Create( | |
| 55 Profile* profile, | |
| 56 SigninManagerBase* signin_manager, | |
| 57 ProfileOAuth2TokenService* token_service) { | |
| 58 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 59 auto instance = | |
| 60 new DevToolsBridgeClient(profile, signin_manager, token_service); | |
| 61 return instance->weak_factory_.GetWeakPtr(); | |
| 62 } | |
| 63 | |
| 64 DevToolsBridgeClient::DevToolsBridgeClient( | |
| 65 Profile* profile, | |
| 66 SigninManagerBase* signin_manager, | |
| 67 ProfileOAuth2TokenService* token_service) | |
| 68 : WebContentsObserver(), | |
| 69 profile_(profile), | |
| 70 identity_provider_(signin_manager, token_service, base::Closure()), | |
| 71 worker_is_loaded_(false), | |
| 72 weak_factory_(this) { | |
| 73 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 74 | |
| 75 identity_provider_.AddObserver(this); | |
| 76 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, | |
| 77 content::Source<Profile>(profile_)); | |
| 78 | |
| 79 if (IsAuthenticated()) | |
| 80 CreateBackgroundWorker(); | |
| 81 } | |
| 82 | |
| 83 DevToolsBridgeClient::~DevToolsBridgeClient() { | |
| 84 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 85 | |
| 86 identity_provider_.RemoveObserver(this); | |
| 87 } | |
| 88 | |
| 89 void DevToolsBridgeClient::DeleteSelf() { | |
| 90 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 91 delete this; | |
| 92 } | |
| 93 | |
| 94 void DevToolsBridgeClient::UpdateBrowserList() { | |
| 95 if (!IsAuthenticated() || browser_list_request_.get()) | |
| 96 return; | |
| 97 browser_list_request_ = CreateGCDApiFlow(); | |
| 98 browser_list_request_->Start( | |
| 99 make_scoped_ptr(new DevToolsBridgeInstancesRequest(this))); | |
| 100 } | |
| 101 | |
| 102 void DevToolsBridgeClient::StartSessionIfNeeded( | |
| 103 const std::string& socket_name) { | |
| 104 if (!background_worker_.get() || !background_worker_->GetWebUI() || | |
| 105 !worker_is_loaded_) { | |
| 106 return; | |
| 107 } | |
| 108 | |
| 109 const size_t kPrefixLength = sizeof(kDeviceIdPrefix) - 1; | |
| 110 if (socket_name.substr(0, kPrefixLength) != kDeviceIdPrefix) | |
| 111 return; | |
| 112 | |
| 113 std::string browser_id = socket_name.substr(kPrefixLength); | |
| 114 background_worker_->GetWebUI()->CallJavascriptFunction( | |
| 115 "WebRTCDeviceProvider.instance.startSessionIfNeeded", | |
| 116 base::StringValue(browser_id)); | |
| 117 } | |
| 118 | |
| 119 // static | |
| 120 DevToolsBridgeClient* DevToolsBridgeClient::FromWebContents( | |
| 121 WebContents* web_contents) { | |
| 122 auto user_data = BackgroundWorkerUserData::FromWebContents(web_contents); | |
| 123 return user_data ? user_data->client() : nullptr; | |
| 124 } | |
| 125 | |
| 126 void DevToolsBridgeClient::RegisterMessageHandlers(content::WebUI* web_ui) { | |
| 127 web_ui->RegisterMessageCallback( | |
| 128 "sendCommand", base::Bind(&DevToolsBridgeClient::HandleSendCommand, | |
| 129 base::Unretained(this))); | |
| 130 } | |
| 131 | |
| 132 bool DevToolsBridgeClient::IsAuthenticated() { | |
| 133 return !identity_provider_.GetActiveAccountId().empty(); | |
| 134 } | |
| 135 | |
| 136 void DevToolsBridgeClient::HandleSendCommand(const base::ListValue* args) { | |
| 137 if (args->GetSize() != 1) | |
| 138 return; | |
| 139 | |
| 140 const base::DictionaryValue* command_value; | |
| 141 if (!args->GetDictionary(0, &command_value)) | |
| 142 return; | |
| 143 | |
| 144 send_command_request_ = CreateGCDApiFlow(); | |
| 145 send_command_request_->Start( | |
| 146 make_scoped_ptr(new SendCommandRequest(command_value, this))); | |
| 147 } | |
| 148 | |
| 149 scoped_ptr<local_discovery::GCDApiFlow> | |
| 150 DevToolsBridgeClient::CreateGCDApiFlow() { | |
| 151 DCHECK(IsAuthenticated()); | |
| 152 return local_discovery::GCDApiFlow::Create( | |
| 153 profile_->GetRequestContext(), identity_provider_.GetTokenService(), | |
| 154 identity_provider_.GetActiveAccountId()); | |
| 155 } | |
| 156 | |
| 157 // static | |
| 158 DevToolsBridgeClient::SerialList DevToolsBridgeClient::GetDevices( | |
| 159 base::WeakPtr<DevToolsBridgeClient> weak_ptr) { | |
| 160 SerialList result; | |
| 161 if (auto* ptr = weak_ptr.get()) { | |
| 162 if (ptr->background_worker_.get()) | |
| 163 result.push_back(kSerial); | |
| 164 | |
| 165 ptr->UpdateBrowserList(); | |
| 166 } | |
| 167 return result; | |
| 168 } | |
| 169 | |
| 170 // static | |
| 171 DevToolsBridgeClient::DeviceInfo DevToolsBridgeClient::GetDeviceInfo( | |
| 172 base::WeakPtr<DevToolsBridgeClient> weak_self, | |
| 173 const std::string& serial) { | |
| 174 DeviceInfo result; | |
| 175 if (auto* self = weak_self.get()) { | |
| 176 result.connected = !!self->background_worker_.get(); | |
| 177 result.model = kPseudoDeviceName; | |
| 178 result.browser_info = self->browsers_; | |
| 179 } | |
| 180 return result; | |
| 181 } | |
| 182 | |
| 183 void DevToolsBridgeClient::CreateBackgroundWorker() { | |
| 184 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 185 | |
| 186 background_worker_.reset( | |
| 187 WebContents::Create(WebContents::CreateParams(profile_))); | |
| 188 | |
| 189 BackgroundWorkerUserData::CreateForWebContents(background_worker_.get()); | |
| 190 BackgroundWorkerUserData::FromWebContents(background_worker_.get()) | |
| 191 ->SetClient(this); | |
| 192 WebContentsObserver::Observe(background_worker_.get()); | |
| 193 | |
| 194 GURL url(kBackgroundWorkerURL); | |
| 195 DCHECK_EQ(chrome::kChromeUIWebRTCDeviceProviderHost, url.host()); | |
| 196 | |
| 197 background_worker_->GetController().LoadURL(url, content::Referrer(), | |
| 198 ui::PAGE_TRANSITION_AUTO_TOPLEVEL, | |
| 199 std::string()); | |
| 200 } | |
| 201 | |
| 202 void DevToolsBridgeClient::DocumentOnLoadCompletedInMainFrame() { | |
| 203 worker_is_loaded_ = true; | |
| 204 } | |
| 205 | |
| 206 void DevToolsBridgeClient::Observe( | |
| 207 int type, | |
| 208 const content::NotificationSource& source, | |
| 209 const content::NotificationDetails& details) { | |
| 210 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 211 DCHECK_EQ(chrome::NOTIFICATION_PROFILE_DESTROYED, type); | |
| 212 | |
| 213 delete this; | |
| 214 } | |
| 215 | |
| 216 void DevToolsBridgeClient::OnActiveAccountLogin() { | |
| 217 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 218 CreateBackgroundWorker(); | |
| 219 } | |
| 220 | |
| 221 void DevToolsBridgeClient::OnActiveAccountLogout() { | |
| 222 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 223 background_worker_.reset(); | |
| 224 browser_list_request_.reset(); | |
| 225 send_command_request_.reset(); | |
| 226 BrowserInfoList().swap(browsers_); | |
| 227 worker_is_loaded_ = false; | |
| 228 } | |
| 229 | |
| 230 void DevToolsBridgeClient::OnCommandSucceeded( | |
| 231 const base::DictionaryValue& response) { | |
| 232 if (background_worker_.get() && background_worker_->GetWebUI()) { | |
| 233 background_worker_->GetWebUI()->CallJavascriptFunction( | |
| 234 "WebRTCDeviceProvider.instance.handleCommandSuccess", response); | |
| 235 } | |
| 236 send_command_request_.reset(); | |
| 237 } | |
| 238 | |
| 239 void DevToolsBridgeClient::OnCommandFailed() { | |
| 240 if (background_worker_.get() && background_worker_->GetWebUI()) { | |
| 241 background_worker_->GetWebUI()->CallJavascriptFunction( | |
| 242 "WebRTCDeviceProvider.instance.handleCommandFailure"); | |
| 243 } | |
| 244 send_command_request_.reset(); | |
| 245 } | |
| 246 | |
| 247 void DevToolsBridgeClient::OnDevToolsBridgeInstancesRequestSucceeded( | |
| 248 const DevToolsBridgeInstancesRequest::InstanceList& instances) { | |
| 249 BrowserInfoList browsers; | |
| 250 for (const auto& instance : instances) { | |
| 251 BrowserInfo browser; | |
| 252 browser.type = BrowserInfo::kTypeChrome; | |
| 253 browser.display_name = instance.display_name; | |
| 254 browser.socket_name = kDeviceIdPrefix + instance.id; | |
| 255 browsers.push_back(browser); | |
| 256 } | |
| 257 browsers_.swap(browsers); | |
| 258 | |
| 259 browser_list_request_.reset(); | |
| 260 | |
| 261 OnBrowserListUpdatedForTests(); | |
| 262 } | |
| 263 | |
| 264 void DevToolsBridgeClient::OnDevToolsBridgeInstancesRequestFailed() { | |
| 265 // We keep the list of remote browsers even if the request failed. | |
| 266 browser_list_request_.reset(); | |
| 267 } | |
| OLD | NEW |