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 |