blob: fce892751a6561c99630d2ee4ccd659e5987a26d [file] [log] [blame]
liaoyuke8b8cfafb2015-06-29 20:41:201// Copyright 2015 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 "remoting/test/app_remoting_connection_helper.h"
6
sergeyu42ad7c02015-12-24 00:20:517#include <utility>
8
liaoyuke8b8cfafb2015-06-29 20:41:209#include "base/json/json_reader.h"
10#include "base/logging.h"
11#include "base/run_loop.h"
gabbac02f52016-05-11 17:55:5112#include "base/threading/thread_task_runner_handle.h"
liaoyuke8b8cfafb2015-06-29 20:41:2013#include "base/timer/timer.h"
14#include "base/values.h"
15#include "remoting/protocol/host_stub.h"
16#include "remoting/test/app_remoting_test_driver_environment.h"
17#include "remoting/test/remote_application_details.h"
18#include "remoting/test/test_chromoting_client.h"
19
20namespace {
21const int kDefaultDPI = 96;
22const int kDefaultWidth = 1024;
23const int kDefaultHeight = 768;
24
25const char kHostProcessWindowTitle[] = "Host Process";
26} // namespace
27
28namespace remoting {
29namespace test {
30
31AppRemotingConnectionHelper::AppRemotingConnectionHelper(
32 const RemoteApplicationDetails& application_details)
33 : application_details_(application_details),
34 connection_is_ready_for_tests_(false),
35 timer_(new base::Timer(true, false)) {
36}
37
38AppRemotingConnectionHelper::~AppRemotingConnectionHelper() {
39 // |client_| destroys some of its members via DeleteSoon on the message loop's
40 // TaskRunner so we need to run the loop until it has no more work to do.
liaoyuke4d6371ea2015-07-27 22:42:4741 if (!connection_is_ready_for_tests_) {
42 client_->RemoveRemoteConnectionObserver(this);
43 }
liaoyuke8b8cfafb2015-06-29 20:41:2044 client_.reset();
45
46 base::RunLoop().RunUntilIdle();
47}
48
liaoyukea3153c12015-07-08 01:31:2049void AppRemotingConnectionHelper::Initialize(
dcheng0765c492016-04-06 22:41:5350 std::unique_ptr<TestChromotingClient> test_chromoting_client) {
sergeyu42ad7c02015-12-24 00:20:5151 client_ = std::move(test_chromoting_client);
liaoyuke8b8cfafb2015-06-29 20:41:2052 client_->AddRemoteConnectionObserver(this);
53}
54
liaoyuke8b8cfafb2015-06-29 20:41:2055bool AppRemotingConnectionHelper::StartConnection() {
56 DCHECK(thread_checker_.CalledOnValidThread());
liaoyukea3153c12015-07-08 01:31:2057 DCHECK(client_);
liaoyuke8b8cfafb2015-06-29 20:41:2058
59 RemoteHostInfo remote_host_info;
60 remoting::test::AppRemotingSharedData->GetRemoteHostInfoForApplicationId(
61 application_details_.application_id, &remote_host_info);
62
63 if (!remote_host_info.IsReadyForConnection()) {
64 return false;
65 }
joedow751a18f32015-07-02 01:39:0966 remoting::test::AppRemotingSharedData->AddHostToReleaseList(
67 application_details_.application_id, remote_host_info.host_id);
liaoyuke8b8cfafb2015-06-29 20:41:2068
69 DCHECK(!run_loop_ || !run_loop_->running());
70 run_loop_.reset(new base::RunLoop());
71
72 // We will wait up to 30 seconds to complete the remote connection and for the
73 // main application window to become visible.
74 DCHECK(!timer_->IsRunning());
75 timer_->Start(FROM_HERE, base::TimeDelta::FromSeconds(30),
76 run_loop_->QuitClosure());
77
joedow910989d2016-12-02 21:15:3278 client_->StartConnection(
79 /*use_test_api_settings=*/false,
80 remote_host_info.GenerateConnectionSetupInfo(
81 AppRemotingSharedData->access_token(),
82 AppRemotingSharedData->user_name()));
liaoyuke8b8cfafb2015-06-29 20:41:2083
84 run_loop_->Run();
85 timer_->Stop();
86
87 if (connection_is_ready_for_tests_) {
88 return true;
89 } else {
90 client_->EndConnection();
91 return false;
92 }
93}
94
95protocol::ClipboardStub* AppRemotingConnectionHelper::clipboard_forwarder() {
96 return client_->clipboard_forwarder();
97}
98
99protocol::HostStub* AppRemotingConnectionHelper::host_stub() {
100 return client_->host_stub();
101}
102
103protocol::InputStub* AppRemotingConnectionHelper::input_stub() {
104 return client_->input_stub();
105}
106
107void AppRemotingConnectionHelper::ConnectionStateChanged(
108 protocol::ConnectionToHost::State state,
109 protocol::ErrorCode error_code) {
110 DCHECK(thread_checker_.CalledOnValidThread());
111
112 // If the connection is closed or failed then mark the connection as closed
113 // and quit the current RunLoop if it exists.
114 if (state == protocol::ConnectionToHost::CLOSED ||
115 state == protocol::ConnectionToHost::FAILED ||
116 error_code != protocol::OK) {
117 connection_is_ready_for_tests_ = false;
118
119 if (run_loop_) {
120 run_loop_->Quit();
121 }
122 }
123}
124
125void AppRemotingConnectionHelper::ConnectionReady(bool ready) {
126 DCHECK(thread_checker_.CalledOnValidThread());
127
128 if (ready) {
129 SendClientConnectionDetailsToHost();
130 } else {
131 // We will only get called here with a false value for |ready| if the video
132 // renderer encounters an error.
133 connection_is_ready_for_tests_ = false;
134
135 if (run_loop_) {
136 run_loop_->Quit();
137 }
138 }
139}
140
141void AppRemotingConnectionHelper::HostMessageReceived(
142 const protocol::ExtensionMessage& message) {
143 DCHECK(thread_checker_.CalledOnValidThread());
144
liaoyuke6e34ea12015-07-23 00:22:25145 VLOG(2) << "HostMessage received by HostMessageReceived()."
146 << " type: " << message.type() << " data: " << message.data();
147
liaoyuke4d6371ea2015-07-27 22:42:47148 if (message.type() == "onWindowAdded") {
liaoyuke8b8cfafb2015-06-29 20:41:20149 HandleOnWindowAddedMessage(message);
150 } else {
joedow9cfae7c2015-07-06 18:44:18151 VLOG(2) << "HostMessage not handled by HostMessageReceived().";
liaoyuke8b8cfafb2015-06-29 20:41:20152 }
153}
154
155void AppRemotingConnectionHelper::SendClientConnectionDetailsToHost() {
156 // First send an access token which will be used for Google Drive access.
157 protocol::ExtensionMessage message;
158 message.set_type("accessToken");
159 message.set_data(AppRemotingSharedData->access_token());
160
joedow9cfae7c2015-07-06 18:44:18161 VLOG(1) << "Sending access token to host";
liaoyuke8b8cfafb2015-06-29 20:41:20162 client_->host_stub()->DeliverClientMessage(message);
163
164 // Next send the host a description of the client screen size.
165 protocol::ClientResolution client_resolution;
sergeyu54624e12016-06-01 10:54:31166 client_resolution.set_width_deprecated(kDefaultWidth);
167 client_resolution.set_height_deprecated(kDefaultHeight);
liaoyuke8b8cfafb2015-06-29 20:41:20168 client_resolution.set_x_dpi(kDefaultDPI);
169 client_resolution.set_y_dpi(kDefaultDPI);
170 client_resolution.set_dips_width(kDefaultWidth);
171 client_resolution.set_dips_height(kDefaultHeight);
172
joedow9cfae7c2015-07-06 18:44:18173 VLOG(1) << "Sending ClientResolution details to host";
liaoyuke8b8cfafb2015-06-29 20:41:20174 client_->host_stub()->NotifyClientResolution(client_resolution);
175
176 // Finally send a message to start sending us video packets.
177 protocol::VideoControl video_control;
178 video_control.set_enable(true);
179
joedow9cfae7c2015-07-06 18:44:18180 VLOG(1) << "Sending enable VideoControl message to host";
liaoyuke8b8cfafb2015-06-29 20:41:20181 client_->host_stub()->ControlVideo(video_control);
182}
183
184void AppRemotingConnectionHelper::HandleOnWindowAddedMessage(
185 const remoting::protocol::ExtensionMessage& message) {
186 DCHECK_EQ(message.type(), "onWindowAdded");
187
188 const base::DictionaryValue* message_data = nullptr;
dcheng0765c492016-04-06 22:41:53189 std::unique_ptr<base::Value> host_message =
190 base::JSONReader::Read(message.data());
liaoyuke8b8cfafb2015-06-29 20:41:20191 if (!host_message.get() || !host_message->GetAsDictionary(&message_data)) {
192 LOG(ERROR) << "onWindowAdded message received was not valid JSON.";
193 if (run_loop_) {
194 run_loop_->Quit();
195 }
196 return;
197 }
198
199 std::string current_window_title;
200 message_data->GetString("title", &current_window_title);
201 if (current_window_title == kHostProcessWindowTitle) {
202 LOG(ERROR) << "Host Process Window is visible, this likely means that the "
203 << "underlying application is in a bad state, YMMV.";
204 }
205
206 std::string main_window_title = application_details_.main_window_title;
207 if (current_window_title.find_first_of(main_window_title) == 0) {
208 connection_is_ready_for_tests_ = true;
liaoyuke4d6371ea2015-07-27 22:42:47209 client_->RemoveRemoteConnectionObserver(this);
liaoyuke8b8cfafb2015-06-29 20:41:20210
211 if (timer_->IsRunning()) {
212 timer_->Stop();
213 }
214
215 DCHECK(run_loop_);
216 // Now that the main window is visible, give the app some time to settle
217 // before signaling that it is ready to run tests.
218 timer_->Start(FROM_HERE, base::TimeDelta::FromSeconds(2),
219 run_loop_->QuitClosure());
220 }
221}
222
223} // namespace test
224} // namespace remoting