Roll src/third_party/skia 21b998b:bda7da8
[chromium-blink-merge.git] / remoting / client / jni / chromoting_jni_runtime.cc
blobc532e74bff0e6ae32a910441d846d736092fed21
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 RegisterJni(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, jclass clazz, jobject context) {
41 base::android::ScopedJavaLocalRef<jobject> context_activity(env, context);
42 base::android::InitApplicationContext(env, context_activity);
44 // The google_apis functions check the command-line arguments to make sure no
45 // runtime API keys have been specified by the environment. Unfortunately, we
46 // neither launch Chromium nor have a command line, so we need to prevent
47 // them from DCHECKing out when they go looking.
48 base::CommandLine::Init(0, nullptr);
50 // Create the singleton now so that the Chromoting threads will be set up.
51 remoting::ChromotingJniRuntime::GetInstance();
54 static jstring GetApiKey(JNIEnv* env, jclass clazz) {
55 return ConvertUTF8ToJavaString(
56 env, google_apis::GetAPIKey().c_str()).Release();
59 static jstring GetClientId(JNIEnv* env, jclass clazz) {
60 return ConvertUTF8ToJavaString(
61 env, google_apis::GetOAuth2ClientID(
62 google_apis::CLIENT_REMOTING).c_str()).Release();
65 static jstring GetClientSecret(JNIEnv* env, jclass clazz) {
66 return ConvertUTF8ToJavaString(
67 env, google_apis::GetOAuth2ClientSecret(
68 google_apis::CLIENT_REMOTING).c_str()).Release();
71 static void Connect(JNIEnv* env,
72 jclass clazz,
73 jstring username,
74 jstring authToken,
75 jstring hostJid,
76 jstring hostId,
77 jstring hostPubkey,
78 jstring pairId,
79 jstring pairSecret,
80 jstring capabilities) {
81 remoting::ChromotingJniRuntime::GetInstance()->ConnectToHost(
82 ConvertJavaStringToUTF8(env, username).c_str(),
83 ConvertJavaStringToUTF8(env, authToken).c_str(),
84 ConvertJavaStringToUTF8(env, hostJid).c_str(),
85 ConvertJavaStringToUTF8(env, hostId).c_str(),
86 ConvertJavaStringToUTF8(env, hostPubkey).c_str(),
87 ConvertJavaStringToUTF8(env, pairId).c_str(),
88 ConvertJavaStringToUTF8(env, pairSecret).c_str(),
89 ConvertJavaStringToUTF8(env, capabilities).c_str());
92 static void Disconnect(JNIEnv* env, jclass clazz) {
93 remoting::ChromotingJniRuntime::GetInstance()->DisconnectFromHost();
96 static void AuthenticationResponse(JNIEnv* env,
97 jclass clazz,
98 jstring pin,
99 jboolean createPair,
100 jstring deviceName) {
101 remoting::ChromotingJniRuntime::GetInstance()->session()->ProvideSecret(
102 ConvertJavaStringToUTF8(env, pin).c_str(), createPair,
103 ConvertJavaStringToUTF8(env, deviceName));
106 static void ScheduleRedraw(JNIEnv* env, jclass clazz) {
107 remoting::ChromotingJniRuntime::GetInstance()->session()->RedrawDesktop();
110 static void SendMouseEvent(JNIEnv* env,
111 jclass clazz,
112 jint x,
113 jint y,
114 jint whichButton,
115 jboolean buttonDown) {
116 // Button must be within the bounds of the MouseEvent_MouseButton enum.
117 DCHECK(whichButton >= 0 && whichButton < 5);
119 remoting::ChromotingJniRuntime::GetInstance()->session()->SendMouseEvent(
120 x, y,
121 static_cast<remoting::protocol::MouseEvent_MouseButton>(whichButton),
122 buttonDown);
125 static void SendMouseWheelEvent(JNIEnv* env,
126 jclass clazz,
127 jint delta_x,
128 jint delta_y) {
129 remoting::ChromotingJniRuntime::GetInstance()->session()->SendMouseWheelEvent(
130 delta_x, delta_y);
133 static jboolean SendKeyEvent(JNIEnv* env,
134 jclass clazz,
135 jint keyCode,
136 jboolean keyDown) {
137 return remoting::ChromotingJniRuntime::GetInstance()->session()->SendKeyEvent(
138 keyCode, keyDown);
141 static void SendTextEvent(JNIEnv* env,
142 jclass clazz,
143 jstring text) {
144 remoting::ChromotingJniRuntime::GetInstance()->session()->SendTextEvent(
145 ConvertJavaStringToUTF8(env, text));
148 static void EnableVideoChannel(JNIEnv* env,
149 jclass clazz,
150 jboolean enable) {
151 remoting::ChromotingJniRuntime::GetInstance()->session()->EnableVideoChannel(
152 enable);
155 static void OnThirdPartyTokenFetched(JNIEnv* env,
156 jclass clazz,
157 jstring token,
158 jstring shared_secret) {
159 ChromotingJniRuntime* runtime = remoting::ChromotingJniRuntime::GetInstance();
160 runtime->network_task_runner()->PostTask(FROM_HERE, base::Bind(
161 &ChromotingJniInstance::HandleOnThirdPartyTokenFetched,
162 runtime->session(),
163 ConvertJavaStringToUTF8(env, token),
164 ConvertJavaStringToUTF8(env, shared_secret)));
167 static void SendExtensionMessage(JNIEnv* env,
168 jclass clazz,
169 jstring type,
170 jstring data) {
171 remoting::ChromotingJniRuntime::GetInstance()->session()->SendClientMessage(
172 ConvertJavaStringToUTF8(env, type),
173 ConvertJavaStringToUTF8(env, data));
176 // ChromotingJniRuntime implementation.
178 // static
179 ChromotingJniRuntime* ChromotingJniRuntime::GetInstance() {
180 return Singleton<ChromotingJniRuntime>::get();
183 ChromotingJniRuntime::ChromotingJniRuntime() {
184 // On Android, the UI thread is managed by Java, so we need to attach and
185 // start a special type of message loop to allow Chromium code to run tasks.
186 ui_loop_.reset(new base::MessageLoopForUI());
187 ui_loop_->Start();
189 // TODO(solb) Stop pretending to control the managed UI thread's lifetime.
190 ui_task_runner_ = new AutoThreadTaskRunner(ui_loop_->task_runner(),
191 base::MessageLoop::QuitClosure());
192 network_task_runner_ = AutoThread::CreateWithType("native_net",
193 ui_task_runner_,
194 base::MessageLoop::TYPE_IO);
195 display_task_runner_ = AutoThread::Create("native_disp",
196 ui_task_runner_);
198 url_requester_ =
199 new URLRequestContextGetter(network_task_runner_, network_task_runner_);
202 ChromotingJniRuntime::~ChromotingJniRuntime() {
203 // The singleton should only ever be destroyed on the main thread.
204 DCHECK(ui_task_runner_->BelongsToCurrentThread());
206 // The session must be shut down first, since it depends on our other
207 // components' still being alive.
208 DisconnectFromHost();
210 base::WaitableEvent done_event(false, false);
211 network_task_runner_->PostTask(FROM_HERE, base::Bind(
212 &ChromotingJniRuntime::DetachFromVmAndSignal,
213 base::Unretained(this),
214 &done_event));
215 done_event.Wait();
216 display_task_runner_->PostTask(FROM_HERE, base::Bind(
217 &ChromotingJniRuntime::DetachFromVmAndSignal,
218 base::Unretained(this),
219 &done_event));
220 done_event.Wait();
221 base::android::LibraryLoaderExitHook();
222 base::android::DetachFromVM();
225 void ChromotingJniRuntime::ConnectToHost(const char* username,
226 const char* auth_token,
227 const char* host_jid,
228 const char* host_id,
229 const char* host_pubkey,
230 const char* pairing_id,
231 const char* pairing_secret,
232 const char* capabilities) {
233 DCHECK(ui_task_runner_->BelongsToCurrentThread());
234 DCHECK(!session_.get());
235 session_ = new ChromotingJniInstance(this,
236 username,
237 auth_token,
238 host_jid,
239 host_id,
240 host_pubkey,
241 pairing_id,
242 pairing_secret,
243 capabilities);
246 void ChromotingJniRuntime::DisconnectFromHost() {
247 DCHECK(ui_task_runner_->BelongsToCurrentThread());
248 if (session_.get()) {
249 session_->Disconnect();
250 session_ = nullptr;
254 void ChromotingJniRuntime::OnConnectionState(
255 protocol::ConnectionToHost::State state,
256 protocol::ErrorCode error) {
257 DCHECK(ui_task_runner_->BelongsToCurrentThread());
259 JNIEnv* env = base::android::AttachCurrentThread();
260 Java_JniInterface_onConnectionState(env, state, error);
263 void ChromotingJniRuntime::DisplayAuthenticationPrompt(bool pairing_supported) {
264 DCHECK(ui_task_runner_->BelongsToCurrentThread());
266 JNIEnv* env = base::android::AttachCurrentThread();
267 Java_JniInterface_displayAuthenticationPrompt(env, pairing_supported);
270 void ChromotingJniRuntime::CommitPairingCredentials(const std::string& host,
271 const std::string& id,
272 const std::string& secret) {
273 DCHECK(ui_task_runner_->BelongsToCurrentThread());
275 JNIEnv* env = base::android::AttachCurrentThread();
276 ScopedJavaLocalRef<jstring> j_host = ConvertUTF8ToJavaString(env, host);
277 ScopedJavaLocalRef<jstring> j_id = ConvertUTF8ToJavaString(env, id);
278 ScopedJavaLocalRef<jstring> j_secret = ConvertUTF8ToJavaString(env,secret);
280 Java_JniInterface_commitPairingCredentials(
281 env, j_host.obj(), j_id.obj(), j_secret.obj());
284 void ChromotingJniRuntime::FetchThirdPartyToken(const GURL& token_url,
285 const std::string& client_id,
286 const std::string& scope) {
287 DCHECK(ui_task_runner_->BelongsToCurrentThread());
288 JNIEnv* env = base::android::AttachCurrentThread();
290 ScopedJavaLocalRef<jstring> j_url =
291 ConvertUTF8ToJavaString(env, token_url.spec());
292 ScopedJavaLocalRef<jstring> j_client_id =
293 ConvertUTF8ToJavaString(env, client_id);
294 ScopedJavaLocalRef<jstring> j_scope = ConvertUTF8ToJavaString(env, scope);
296 Java_JniInterface_fetchThirdPartyToken(
297 env, j_url.obj(), j_client_id.obj(), j_scope.obj());
300 void ChromotingJniRuntime::SetCapabilities(const std::string& capabilities) {
301 DCHECK(ui_task_runner_->BelongsToCurrentThread());
302 JNIEnv* env = base::android::AttachCurrentThread();
304 ScopedJavaLocalRef<jstring> j_cap =
305 ConvertUTF8ToJavaString(env, capabilities);
307 Java_JniInterface_setCapabilities(env, j_cap.obj());
310 void ChromotingJniRuntime::HandleExtensionMessage(const std::string& type,
311 const std::string& message) {
312 DCHECK(ui_task_runner_->BelongsToCurrentThread());
313 JNIEnv* env = base::android::AttachCurrentThread();
315 ScopedJavaLocalRef<jstring> j_type = ConvertUTF8ToJavaString(env, type);
316 ScopedJavaLocalRef<jstring> j_message = ConvertUTF8ToJavaString(env, message);
318 Java_JniInterface_handleExtensionMessage(env, j_type.obj(), j_message.obj());
321 base::android::ScopedJavaLocalRef<jobject> ChromotingJniRuntime::NewBitmap(
322 int width, int height) {
323 JNIEnv* env = base::android::AttachCurrentThread();
324 return Java_JniInterface_newBitmap(env, width, height);
327 void ChromotingJniRuntime::UpdateFrameBitmap(jobject bitmap) {
328 DCHECK(display_task_runner_->BelongsToCurrentThread());
330 JNIEnv* env = base::android::AttachCurrentThread();
331 Java_JniInterface_setVideoFrame(env, bitmap);
334 void ChromotingJniRuntime::UpdateCursorShape(
335 const protocol::CursorShapeInfo& cursor_shape) {
336 DCHECK(display_task_runner_->BelongsToCurrentThread());
338 // const_cast<> is safe as long as the Java updateCursorShape() method copies
339 // the data out of the buffer without mutating it, and doesn't keep any
340 // reference to the buffer afterwards. Unfortunately, there seems to be no way
341 // to create a read-only ByteBuffer from a pointer-to-const.
342 char* data = string_as_array(const_cast<std::string*>(&cursor_shape.data()));
343 int cursor_total_bytes =
344 cursor_shape.width() * cursor_shape.height() * kBytesPerPixel;
346 JNIEnv* env = base::android::AttachCurrentThread();
347 base::android::ScopedJavaLocalRef<jobject> buffer(env,
348 env->NewDirectByteBuffer(data, cursor_total_bytes));
349 Java_JniInterface_updateCursorShape(env,
350 cursor_shape.width(),
351 cursor_shape.height(),
352 cursor_shape.hotspot_x(),
353 cursor_shape.hotspot_y(),
354 buffer.obj());
357 void ChromotingJniRuntime::RedrawCanvas() {
358 DCHECK(display_task_runner_->BelongsToCurrentThread());
360 JNIEnv* env = base::android::AttachCurrentThread();
361 Java_JniInterface_redrawGraphicsInternal(env);
364 void ChromotingJniRuntime::DetachFromVmAndSignal(base::WaitableEvent* waiter) {
365 base::android::DetachFromVM();
366 waiter->Signal();
368 } // namespace remoting