Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / remoting / client / jni / chromoting_jni_runtime.cc
blobaf90692eaefcf5ea136498aef265041bd9cbb4e3
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/library_loader/library_loader_hooks.h"
11 #include "base/android/scoped_java_ref.h"
12 #include "base/basictypes.h"
13 #include "base/command_line.h"
14 #include "base/memory/singleton.h"
15 #include "base/stl_util.h"
16 #include "base/synchronization/waitable_event.h"
17 #include "google_apis/google_api_keys.h"
18 #include "jni/JniInterface_jni.h"
19 #include "remoting/base/url_request_context_getter.h"
21 using base::android::ConvertJavaStringToUTF8;
22 using base::android::ConvertUTF8ToJavaString;
23 using base::android::ToJavaByteArray;
25 namespace {
27 const int kBytesPerPixel = 4;
29 } // namespace
31 namespace remoting {
33 bool RegisterChromotingJniRuntime(JNIEnv* env) {
34 return remoting::RegisterNativesImpl(env);
37 // Implementation of stubs defined in JniInterface_jni.h. These are the entry
38 // points for JNI calls from Java into C++.
40 static void LoadNative(JNIEnv* env,
41 const JavaParamRef<jclass>& clazz,
42 const JavaParamRef<jobject>& context) {
43 base::android::InitApplicationContext(env, context);
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, nullptr);
51 // Create the singleton now so that the Chromoting threads will be set up.
52 remoting::ChromotingJniRuntime::GetInstance();
55 static ScopedJavaLocalRef<jstring> GetApiKey(
56 JNIEnv* env,
57 const JavaParamRef<jclass>& clazz) {
58 return ConvertUTF8ToJavaString(env, google_apis::GetAPIKey().c_str());
61 static ScopedJavaLocalRef<jstring> GetClientId(
62 JNIEnv* env,
63 const JavaParamRef<jclass>& clazz) {
64 return ConvertUTF8ToJavaString(
65 env,
66 google_apis::GetOAuth2ClientID(google_apis::CLIENT_REMOTING).c_str());
69 static ScopedJavaLocalRef<jstring> GetClientSecret(
70 JNIEnv* env,
71 const JavaParamRef<jclass>& clazz) {
72 return ConvertUTF8ToJavaString(
73 env,
74 google_apis::GetOAuth2ClientSecret(google_apis::CLIENT_REMOTING).c_str());
77 static void Connect(JNIEnv* env,
78 const JavaParamRef<jclass>& clazz,
79 const JavaParamRef<jstring>& username,
80 const JavaParamRef<jstring>& authToken,
81 const JavaParamRef<jstring>& hostJid,
82 const JavaParamRef<jstring>& hostId,
83 const JavaParamRef<jstring>& hostPubkey,
84 const JavaParamRef<jstring>& pairId,
85 const JavaParamRef<jstring>& pairSecret,
86 const JavaParamRef<jstring>& capabilities) {
87 remoting::ChromotingJniRuntime::GetInstance()->ConnectToHost(
88 ConvertJavaStringToUTF8(env, username).c_str(),
89 ConvertJavaStringToUTF8(env, authToken).c_str(),
90 ConvertJavaStringToUTF8(env, hostJid).c_str(),
91 ConvertJavaStringToUTF8(env, hostId).c_str(),
92 ConvertJavaStringToUTF8(env, hostPubkey).c_str(),
93 ConvertJavaStringToUTF8(env, pairId).c_str(),
94 ConvertJavaStringToUTF8(env, pairSecret).c_str(),
95 ConvertJavaStringToUTF8(env, capabilities).c_str());
98 static void Disconnect(JNIEnv* env, const JavaParamRef<jclass>& clazz) {
99 remoting::ChromotingJniRuntime::GetInstance()->DisconnectFromHost();
102 static void AuthenticationResponse(JNIEnv* env,
103 const JavaParamRef<jclass>& clazz,
104 const JavaParamRef<jstring>& pin,
105 jboolean createPair,
106 const JavaParamRef<jstring>& deviceName) {
107 remoting::ChromotingJniRuntime::GetInstance()->session()->ProvideSecret(
108 ConvertJavaStringToUTF8(env, pin).c_str(), createPair,
109 ConvertJavaStringToUTF8(env, deviceName));
112 static void ScheduleRedraw(JNIEnv* env, const JavaParamRef<jclass>& clazz) {
113 remoting::ChromotingJniRuntime::GetInstance()->session()->RedrawDesktop();
116 static void SendMouseEvent(JNIEnv* env,
117 const JavaParamRef<jclass>& clazz,
118 jint x,
119 jint y,
120 jint whichButton,
121 jboolean buttonDown) {
122 // Button must be within the bounds of the MouseEvent_MouseButton enum.
123 DCHECK(whichButton >= 0 && whichButton < 5);
125 remoting::ChromotingJniRuntime::GetInstance()->session()->SendMouseEvent(
126 x, y,
127 static_cast<remoting::protocol::MouseEvent_MouseButton>(whichButton),
128 buttonDown);
131 static void SendMouseWheelEvent(JNIEnv* env,
132 const JavaParamRef<jclass>& clazz,
133 jint delta_x,
134 jint delta_y) {
135 remoting::ChromotingJniRuntime::GetInstance()->session()->SendMouseWheelEvent(
136 delta_x, delta_y);
139 static jboolean SendKeyEvent(JNIEnv* env,
140 const JavaParamRef<jclass>& clazz,
141 jint scanCode,
142 jint keyCode,
143 jboolean keyDown) {
144 return remoting::ChromotingJniRuntime::GetInstance()->session()->SendKeyEvent(
145 scanCode, keyCode, keyDown);
148 static void SendTextEvent(JNIEnv* env,
149 const JavaParamRef<jclass>& clazz,
150 const JavaParamRef<jstring>& text) {
151 remoting::ChromotingJniRuntime::GetInstance()->session()->SendTextEvent(
152 ConvertJavaStringToUTF8(env, text));
155 static void EnableVideoChannel(JNIEnv* env,
156 const JavaParamRef<jclass>& clazz,
157 jboolean enable) {
158 remoting::ChromotingJniRuntime::GetInstance()->session()->EnableVideoChannel(
159 enable);
162 static void OnThirdPartyTokenFetched(
163 JNIEnv* env,
164 const JavaParamRef<jclass>& clazz,
165 const JavaParamRef<jstring>& token,
166 const JavaParamRef<jstring>& shared_secret) {
167 ChromotingJniRuntime* runtime = remoting::ChromotingJniRuntime::GetInstance();
168 runtime->network_task_runner()->PostTask(FROM_HERE, base::Bind(
169 &ChromotingJniInstance::HandleOnThirdPartyTokenFetched,
170 runtime->session(),
171 ConvertJavaStringToUTF8(env, token),
172 ConvertJavaStringToUTF8(env, shared_secret)));
175 static void SendExtensionMessage(JNIEnv* env,
176 const JavaParamRef<jclass>& clazz,
177 const JavaParamRef<jstring>& type,
178 const JavaParamRef<jstring>& data) {
179 remoting::ChromotingJniRuntime::GetInstance()->session()->SendClientMessage(
180 ConvertJavaStringToUTF8(env, type),
181 ConvertJavaStringToUTF8(env, data));
184 // ChromotingJniRuntime implementation.
186 // static
187 ChromotingJniRuntime* ChromotingJniRuntime::GetInstance() {
188 return base::Singleton<ChromotingJniRuntime>::get();
191 ChromotingJniRuntime::ChromotingJniRuntime() {
192 // On Android, the UI thread is managed by Java, so we need to attach and
193 // start a special type of message loop to allow Chromium code to run tasks.
194 ui_loop_.reset(new base::MessageLoopForUI());
195 ui_loop_->Start();
197 // TODO(solb) Stop pretending to control the managed UI thread's lifetime.
198 ui_task_runner_ = new AutoThreadTaskRunner(ui_loop_->task_runner(),
199 base::MessageLoop::QuitClosure());
200 network_task_runner_ = AutoThread::CreateWithType("native_net",
201 ui_task_runner_,
202 base::MessageLoop::TYPE_IO);
203 display_task_runner_ = AutoThread::Create("native_disp",
204 ui_task_runner_);
206 url_requester_ =
207 new URLRequestContextGetter(network_task_runner_, network_task_runner_);
210 ChromotingJniRuntime::~ChromotingJniRuntime() {
211 // The singleton should only ever be destroyed on the main thread.
212 DCHECK(ui_task_runner_->BelongsToCurrentThread());
214 // The session must be shut down first, since it depends on our other
215 // components' still being alive.
216 DisconnectFromHost();
218 base::WaitableEvent done_event(false, false);
219 network_task_runner_->PostTask(FROM_HERE, base::Bind(
220 &ChromotingJniRuntime::DetachFromVmAndSignal,
221 base::Unretained(this),
222 &done_event));
223 done_event.Wait();
224 display_task_runner_->PostTask(FROM_HERE, base::Bind(
225 &ChromotingJniRuntime::DetachFromVmAndSignal,
226 base::Unretained(this),
227 &done_event));
228 done_event.Wait();
229 base::android::LibraryLoaderExitHook();
230 base::android::DetachFromVM();
233 void ChromotingJniRuntime::ConnectToHost(const char* username,
234 const char* auth_token,
235 const char* host_jid,
236 const char* host_id,
237 const char* host_pubkey,
238 const char* pairing_id,
239 const char* pairing_secret,
240 const char* capabilities) {
241 DCHECK(ui_task_runner_->BelongsToCurrentThread());
242 DCHECK(!session_.get());
243 session_ = new ChromotingJniInstance(this,
244 username,
245 auth_token,
246 host_jid,
247 host_id,
248 host_pubkey,
249 pairing_id,
250 pairing_secret,
251 capabilities);
254 void ChromotingJniRuntime::DisconnectFromHost() {
255 DCHECK(ui_task_runner_->BelongsToCurrentThread());
256 if (session_.get()) {
257 session_->Disconnect();
258 session_ = nullptr;
262 void ChromotingJniRuntime::OnConnectionState(
263 protocol::ConnectionToHost::State state,
264 protocol::ErrorCode error) {
265 DCHECK(ui_task_runner_->BelongsToCurrentThread());
267 JNIEnv* env = base::android::AttachCurrentThread();
268 Java_JniInterface_onConnectionState(env, state, error);
271 void ChromotingJniRuntime::DisplayAuthenticationPrompt(bool pairing_supported) {
272 DCHECK(ui_task_runner_->BelongsToCurrentThread());
274 JNIEnv* env = base::android::AttachCurrentThread();
275 Java_JniInterface_displayAuthenticationPrompt(env, pairing_supported);
278 void ChromotingJniRuntime::CommitPairingCredentials(const std::string& host,
279 const std::string& id,
280 const std::string& secret) {
281 DCHECK(ui_task_runner_->BelongsToCurrentThread());
283 JNIEnv* env = base::android::AttachCurrentThread();
284 ScopedJavaLocalRef<jstring> j_host = ConvertUTF8ToJavaString(env, host);
285 ScopedJavaLocalRef<jstring> j_id = ConvertUTF8ToJavaString(env, id);
286 ScopedJavaLocalRef<jstring> j_secret = ConvertUTF8ToJavaString(env,secret);
288 Java_JniInterface_commitPairingCredentials(
289 env, j_host.obj(), j_id.obj(), j_secret.obj());
292 void ChromotingJniRuntime::FetchThirdPartyToken(const GURL& token_url,
293 const std::string& client_id,
294 const std::string& scope) {
295 DCHECK(ui_task_runner_->BelongsToCurrentThread());
296 JNIEnv* env = base::android::AttachCurrentThread();
298 ScopedJavaLocalRef<jstring> j_url =
299 ConvertUTF8ToJavaString(env, token_url.spec());
300 ScopedJavaLocalRef<jstring> j_client_id =
301 ConvertUTF8ToJavaString(env, client_id);
302 ScopedJavaLocalRef<jstring> j_scope = ConvertUTF8ToJavaString(env, scope);
304 Java_JniInterface_fetchThirdPartyToken(
305 env, j_url.obj(), j_client_id.obj(), j_scope.obj());
308 void ChromotingJniRuntime::SetCapabilities(const std::string& capabilities) {
309 DCHECK(ui_task_runner_->BelongsToCurrentThread());
310 JNIEnv* env = base::android::AttachCurrentThread();
312 ScopedJavaLocalRef<jstring> j_cap =
313 ConvertUTF8ToJavaString(env, capabilities);
315 Java_JniInterface_setCapabilities(env, j_cap.obj());
318 void ChromotingJniRuntime::HandleExtensionMessage(const std::string& type,
319 const std::string& message) {
320 DCHECK(ui_task_runner_->BelongsToCurrentThread());
321 JNIEnv* env = base::android::AttachCurrentThread();
323 ScopedJavaLocalRef<jstring> j_type = ConvertUTF8ToJavaString(env, type);
324 ScopedJavaLocalRef<jstring> j_message = ConvertUTF8ToJavaString(env, message);
326 Java_JniInterface_handleExtensionMessage(env, j_type.obj(), j_message.obj());
329 base::android::ScopedJavaLocalRef<jobject> ChromotingJniRuntime::NewBitmap(
330 int width, int height) {
331 JNIEnv* env = base::android::AttachCurrentThread();
332 return Java_JniInterface_newBitmap(env, width, height);
335 void ChromotingJniRuntime::UpdateFrameBitmap(jobject bitmap) {
336 DCHECK(display_task_runner_->BelongsToCurrentThread());
338 JNIEnv* env = base::android::AttachCurrentThread();
339 Java_JniInterface_setVideoFrame(env, bitmap);
342 void ChromotingJniRuntime::UpdateCursorShape(
343 const protocol::CursorShapeInfo& cursor_shape) {
344 DCHECK(display_task_runner_->BelongsToCurrentThread());
346 // const_cast<> is safe as long as the Java updateCursorShape() method copies
347 // the data out of the buffer without mutating it, and doesn't keep any
348 // reference to the buffer afterwards. Unfortunately, there seems to be no way
349 // to create a read-only ByteBuffer from a pointer-to-const.
350 char* data = string_as_array(const_cast<std::string*>(&cursor_shape.data()));
351 int cursor_total_bytes =
352 cursor_shape.width() * cursor_shape.height() * kBytesPerPixel;
354 JNIEnv* env = base::android::AttachCurrentThread();
355 base::android::ScopedJavaLocalRef<jobject> buffer(env,
356 env->NewDirectByteBuffer(data, cursor_total_bytes));
357 Java_JniInterface_updateCursorShape(env,
358 cursor_shape.width(),
359 cursor_shape.height(),
360 cursor_shape.hotspot_x(),
361 cursor_shape.hotspot_y(),
362 buffer.obj());
365 void ChromotingJniRuntime::RedrawCanvas() {
366 DCHECK(display_task_runner_->BelongsToCurrentThread());
368 JNIEnv* env = base::android::AttachCurrentThread();
369 Java_JniInterface_redrawGraphicsInternal(env);
372 void ChromotingJniRuntime::DetachFromVmAndSignal(base::WaitableEvent* waiter) {
373 base::android::DetachFromVM();
374 waiter->Signal();
376 } // namespace remoting