Blink roll 25b6bd3a7a131ffe68d809546ad1a20707915cdc:3a503f41ae42e5b79cfcd2ff10e65afde...
[chromium-blink-merge.git] / remoting / client / jni / chromoting_jni_runtime.cc
blob38834dd06d033b5bc728ac02e30e1bbaf5a9c2c2
1 // Copyright 2013 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.
5 #include "remoting/client/jni/chromoting_jni_runtime.h"
7 #include "base/android/jni_android.h"
8 #include "base/android/jni_array.h"
9 #include "base/android/jni_string.h"
10 #include "base/android/scoped_java_ref.h"
11 #include "base/basictypes.h"
12 #include "base/command_line.h"
13 #include "base/memory/singleton.h"
14 #include "base/stl_util.h"
15 #include "base/synchronization/waitable_event.h"
16 #include "google_apis/google_api_keys.h"
17 #include "jni/JniInterface_jni.h"
18 #include "media/base/yuv_convert.h"
19 #include "remoting/base/url_request_context_getter.h"
20 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
22 using base::android::ConvertJavaStringToUTF8;
23 using base::android::ConvertUTF8ToJavaString;
24 using base::android::ToJavaByteArray;
26 namespace {
28 const int kBytesPerPixel = 4;
30 } // namespace
32 namespace remoting {
34 bool RegisterJni(JNIEnv* env) {
35 return remoting::RegisterNativesImpl(env);
38 // Implementation of stubs defined in JniInterface_jni.h. These are the entry
39 // points for JNI calls from Java into C++.
41 static void LoadNative(JNIEnv* env, jclass clazz, jobject context) {
42 base::android::ScopedJavaLocalRef<jobject> context_activity(env, context);
43 base::android::InitApplicationContext(env, context_activity);
45 // The google_apis functions check the command-line arguments to make sure no
46 // runtime API keys have been specified by the environment. Unfortunately, we
47 // neither launch Chromium nor have a command line, so we need to prevent
48 // them from DCHECKing out when they go looking.
49 base::CommandLine::Init(0, NULL);
51 // Create the singleton now so that the Chromoting threads will be set up.
52 remoting::ChromotingJniRuntime::GetInstance();
55 static jstring GetApiKey(JNIEnv* env, jclass clazz) {
56 return ConvertUTF8ToJavaString(
57 env, google_apis::GetAPIKey().c_str()).Release();
60 static jstring GetClientId(JNIEnv* env, jclass clazz) {
61 return ConvertUTF8ToJavaString(
62 env, google_apis::GetOAuth2ClientID(
63 google_apis::CLIENT_REMOTING).c_str()).Release();
66 static jstring GetClientSecret(JNIEnv* env, jclass clazz) {
67 return ConvertUTF8ToJavaString(
68 env, google_apis::GetOAuth2ClientSecret(
69 google_apis::CLIENT_REMOTING).c_str()).Release();
72 static void Connect(JNIEnv* env,
73 jclass clazz,
74 jstring username,
75 jstring authToken,
76 jstring hostJid,
77 jstring hostId,
78 jstring hostPubkey,
79 jstring pairId,
80 jstring pairSecret,
81 jstring capabilities) {
82 remoting::ChromotingJniRuntime::GetInstance()->ConnectToHost(
83 ConvertJavaStringToUTF8(env, username).c_str(),
84 ConvertJavaStringToUTF8(env, authToken).c_str(),
85 ConvertJavaStringToUTF8(env, hostJid).c_str(),
86 ConvertJavaStringToUTF8(env, hostId).c_str(),
87 ConvertJavaStringToUTF8(env, hostPubkey).c_str(),
88 ConvertJavaStringToUTF8(env, pairId).c_str(),
89 ConvertJavaStringToUTF8(env, pairSecret).c_str(),
90 ConvertJavaStringToUTF8(env, capabilities).c_str());
93 static void Disconnect(JNIEnv* env, jclass clazz) {
94 remoting::ChromotingJniRuntime::GetInstance()->DisconnectFromHost();
97 static void AuthenticationResponse(JNIEnv* env,
98 jclass clazz,
99 jstring pin,
100 jboolean createPair,
101 jstring deviceName) {
102 remoting::ChromotingJniRuntime::GetInstance()->session()->ProvideSecret(
103 ConvertJavaStringToUTF8(env, pin).c_str(), createPair,
104 ConvertJavaStringToUTF8(env, deviceName));
107 static void ScheduleRedraw(JNIEnv* env, jclass clazz) {
108 remoting::ChromotingJniRuntime::GetInstance()->session()->RedrawDesktop();
111 static void SendMouseEvent(JNIEnv* env,
112 jclass clazz,
113 jint x,
114 jint y,
115 jint whichButton,
116 jboolean buttonDown) {
117 // Button must be within the bounds of the MouseEvent_MouseButton enum.
118 DCHECK(whichButton >= 0 && whichButton < 5);
120 remoting::ChromotingJniRuntime::GetInstance()->session()->SendMouseEvent(
121 x, y,
122 static_cast<remoting::protocol::MouseEvent_MouseButton>(whichButton),
123 buttonDown);
126 static void SendMouseWheelEvent(JNIEnv* env,
127 jclass clazz,
128 jint delta_x,
129 jint delta_y) {
130 remoting::ChromotingJniRuntime::GetInstance()->session()->SendMouseWheelEvent(
131 delta_x, delta_y);
134 static jboolean SendKeyEvent(JNIEnv* env,
135 jclass clazz,
136 jint keyCode,
137 jboolean keyDown) {
138 return remoting::ChromotingJniRuntime::GetInstance()->session()->SendKeyEvent(
139 keyCode, keyDown);
142 static void SendTextEvent(JNIEnv* env,
143 jclass clazz,
144 jstring text) {
145 remoting::ChromotingJniRuntime::GetInstance()->session()->SendTextEvent(
146 ConvertJavaStringToUTF8(env, text));
149 static void OnThirdPartyTokenFetched(JNIEnv* env,
150 jclass clazz,
151 jstring token,
152 jstring shared_secret) {
153 ChromotingJniRuntime* runtime = remoting::ChromotingJniRuntime::GetInstance();
154 runtime->network_task_runner()->PostTask(FROM_HERE, base::Bind(
155 &ChromotingJniInstance::HandleOnThirdPartyTokenFetched,
156 runtime->session(),
157 ConvertJavaStringToUTF8(env, token),
158 ConvertJavaStringToUTF8(env, shared_secret)));
161 static void SendExtensionMessage(JNIEnv* env,
162 jclass clazz,
163 jstring type,
164 jstring data) {
165 remoting::ChromotingJniRuntime::GetInstance()->session()->SendClientMessage(
166 ConvertJavaStringToUTF8(env, type),
167 ConvertJavaStringToUTF8(env, data));
170 // ChromotingJniRuntime implementation.
172 // static
173 ChromotingJniRuntime* ChromotingJniRuntime::GetInstance() {
174 return Singleton<ChromotingJniRuntime>::get();
177 ChromotingJniRuntime::ChromotingJniRuntime() {
178 at_exit_manager_.reset(new base::AtExitManager());
180 // On Android, the UI thread is managed by Java, so we need to attach and
181 // start a special type of message loop to allow Chromium code to run tasks.
182 ui_loop_.reset(new base::MessageLoopForUI());
183 ui_loop_->Start();
185 // TODO(solb) Stop pretending to control the managed UI thread's lifetime.
186 ui_task_runner_ = new AutoThreadTaskRunner(ui_loop_->message_loop_proxy(),
187 base::MessageLoop::QuitClosure());
188 network_task_runner_ = AutoThread::CreateWithType("native_net",
189 ui_task_runner_,
190 base::MessageLoop::TYPE_IO);
191 display_task_runner_ = AutoThread::Create("native_disp",
192 ui_task_runner_);
194 url_requester_ =
195 new URLRequestContextGetter(network_task_runner_, network_task_runner_);
197 // Allows later decoding of video frames.
198 media::InitializeCPUSpecificYUVConversions();
201 ChromotingJniRuntime::~ChromotingJniRuntime() {
202 // The singleton should only ever be destroyed on the main thread.
203 DCHECK(ui_task_runner_->BelongsToCurrentThread());
205 // The session must be shut down first, since it depends on our other
206 // components' still being alive.
207 DisconnectFromHost();
209 base::WaitableEvent done_event(false, false);
210 network_task_runner_->PostTask(FROM_HERE, base::Bind(
211 &ChromotingJniRuntime::DetachFromVmAndSignal,
212 base::Unretained(this),
213 &done_event));
214 done_event.Wait();
215 display_task_runner_->PostTask(FROM_HERE, base::Bind(
216 &ChromotingJniRuntime::DetachFromVmAndSignal,
217 base::Unretained(this),
218 &done_event));
219 done_event.Wait();
220 base::android::DetachFromVM();
223 void ChromotingJniRuntime::ConnectToHost(const char* username,
224 const char* auth_token,
225 const char* host_jid,
226 const char* host_id,
227 const char* host_pubkey,
228 const char* pairing_id,
229 const char* pairing_secret,
230 const char* capabilities) {
231 DCHECK(ui_task_runner_->BelongsToCurrentThread());
232 DCHECK(!session_.get());
233 session_ = new ChromotingJniInstance(this,
234 username,
235 auth_token,
236 host_jid,
237 host_id,
238 host_pubkey,
239 pairing_id,
240 pairing_secret,
241 capabilities);
244 void ChromotingJniRuntime::DisconnectFromHost() {
245 DCHECK(ui_task_runner_->BelongsToCurrentThread());
246 if (session_.get()) {
247 session_->Disconnect();
248 session_ = NULL;
252 void ChromotingJniRuntime::OnConnectionState(
253 protocol::ConnectionToHost::State state,
254 protocol::ErrorCode error) {
255 DCHECK(ui_task_runner_->BelongsToCurrentThread());
257 JNIEnv* env = base::android::AttachCurrentThread();
258 Java_JniInterface_onConnectionState(env, state, error);
261 void ChromotingJniRuntime::DisplayAuthenticationPrompt(bool pairing_supported) {
262 DCHECK(ui_task_runner_->BelongsToCurrentThread());
264 JNIEnv* env = base::android::AttachCurrentThread();
265 Java_JniInterface_displayAuthenticationPrompt(env, pairing_supported);
268 void ChromotingJniRuntime::CommitPairingCredentials(const std::string& host,
269 const std::string& id,
270 const std::string& secret) {
271 DCHECK(ui_task_runner_->BelongsToCurrentThread());
273 JNIEnv* env = base::android::AttachCurrentThread();
274 ScopedJavaLocalRef<jstring> j_host = ConvertUTF8ToJavaString(env, host);
275 ScopedJavaLocalRef<jstring> j_id = ConvertUTF8ToJavaString(env, id);
276 ScopedJavaLocalRef<jstring> j_secret = ConvertUTF8ToJavaString(env,secret);
278 Java_JniInterface_commitPairingCredentials(
279 env, j_host.obj(), j_id.obj(), j_secret.obj());
282 void ChromotingJniRuntime::FetchThirdPartyToken(const GURL& token_url,
283 const std::string& client_id,
284 const std::string& scope) {
285 DCHECK(ui_task_runner_->BelongsToCurrentThread());
286 JNIEnv* env = base::android::AttachCurrentThread();
288 ScopedJavaLocalRef<jstring> j_url =
289 ConvertUTF8ToJavaString(env, token_url.spec());
290 ScopedJavaLocalRef<jstring> j_client_id =
291 ConvertUTF8ToJavaString(env, client_id);
292 ScopedJavaLocalRef<jstring> j_scope = ConvertUTF8ToJavaString(env, scope);
294 Java_JniInterface_fetchThirdPartyToken(
295 env, j_url.obj(), j_client_id.obj(), j_scope.obj());
298 void ChromotingJniRuntime::SetCapabilities(const std::string& capabilities) {
299 DCHECK(ui_task_runner_->BelongsToCurrentThread());
300 JNIEnv* env = base::android::AttachCurrentThread();
302 ScopedJavaLocalRef<jstring> j_cap =
303 ConvertUTF8ToJavaString(env, capabilities);
305 Java_JniInterface_setCapabilities(env, j_cap.obj());
308 void ChromotingJniRuntime::HandleExtensionMessage(const std::string& type,
309 const std::string& message) {
310 DCHECK(ui_task_runner_->BelongsToCurrentThread());
311 JNIEnv* env = base::android::AttachCurrentThread();
313 ScopedJavaLocalRef<jstring> j_type = ConvertUTF8ToJavaString(env, type);
314 ScopedJavaLocalRef<jstring> j_message = ConvertUTF8ToJavaString(env, message);
316 Java_JniInterface_handleExtensionMessage(env, j_type.obj(), j_message.obj());
319 base::android::ScopedJavaLocalRef<jobject> ChromotingJniRuntime::NewBitmap(
320 webrtc::DesktopSize size) {
321 JNIEnv* env = base::android::AttachCurrentThread();
322 return Java_JniInterface_newBitmap(env, size.width(), size.height());
325 void ChromotingJniRuntime::UpdateFrameBitmap(jobject bitmap) {
326 DCHECK(display_task_runner_->BelongsToCurrentThread());
328 JNIEnv* env = base::android::AttachCurrentThread();
329 Java_JniInterface_setVideoFrame(env, bitmap);
332 void ChromotingJniRuntime::UpdateCursorShape(
333 const protocol::CursorShapeInfo& cursor_shape) {
334 DCHECK(display_task_runner_->BelongsToCurrentThread());
336 // const_cast<> is safe as long as the Java updateCursorShape() method copies
337 // the data out of the buffer without mutating it, and doesn't keep any
338 // reference to the buffer afterwards. Unfortunately, there seems to be no way
339 // to create a read-only ByteBuffer from a pointer-to-const.
340 char* data = string_as_array(const_cast<std::string*>(&cursor_shape.data()));
341 int cursor_total_bytes =
342 cursor_shape.width() * cursor_shape.height() * kBytesPerPixel;
344 JNIEnv* env = base::android::AttachCurrentThread();
345 base::android::ScopedJavaLocalRef<jobject> buffer(env,
346 env->NewDirectByteBuffer(data, cursor_total_bytes));
347 Java_JniInterface_updateCursorShape(env,
348 cursor_shape.width(),
349 cursor_shape.height(),
350 cursor_shape.hotspot_x(),
351 cursor_shape.hotspot_y(),
352 buffer.obj());
355 void ChromotingJniRuntime::RedrawCanvas() {
356 DCHECK(display_task_runner_->BelongsToCurrentThread());
358 JNIEnv* env = base::android::AttachCurrentThread();
359 Java_JniInterface_redrawGraphicsInternal(env);
362 void ChromotingJniRuntime::DetachFromVmAndSignal(base::WaitableEvent* waiter) {
363 base::android::DetachFromVM();
364 waiter->Signal();
366 } // namespace remoting