Synchronize Android relocation packer source with AOSP.
[chromium-blink-merge.git] / remoting / client / jni / chromoting_jni_runtime.cc
bloba9b91270302e51203f67302a6d3d6ebc4004c9b9
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 "media/base/yuv_convert.h"
20 #include "remoting/base/url_request_context_getter.h"
21 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
23 using base::android::ConvertJavaStringToUTF8;
24 using base::android::ConvertUTF8ToJavaString;
25 using base::android::ToJavaByteArray;
27 namespace {
29 const int kBytesPerPixel = 4;
31 } // namespace
33 namespace remoting {
35 bool RegisterJni(JNIEnv* env) {
36 return remoting::RegisterNativesImpl(env);
39 // Implementation of stubs defined in JniInterface_jni.h. These are the entry
40 // points for JNI calls from Java into C++.
42 static void LoadNative(JNIEnv* env, jclass clazz, jobject context) {
43 base::android::ScopedJavaLocalRef<jobject> context_activity(env, context);
44 base::android::InitApplicationContext(env, context_activity);
46 // The google_apis functions check the command-line arguments to make sure no
47 // runtime API keys have been specified by the environment. Unfortunately, we
48 // neither launch Chromium nor have a command line, so we need to prevent
49 // them from DCHECKing out when they go looking.
50 base::CommandLine::Init(0, nullptr);
52 // Create the singleton now so that the Chromoting threads will be set up.
53 remoting::ChromotingJniRuntime::GetInstance();
56 static jstring GetApiKey(JNIEnv* env, jclass clazz) {
57 return ConvertUTF8ToJavaString(
58 env, google_apis::GetAPIKey().c_str()).Release();
61 static jstring GetClientId(JNIEnv* env, jclass clazz) {
62 return ConvertUTF8ToJavaString(
63 env, google_apis::GetOAuth2ClientID(
64 google_apis::CLIENT_REMOTING).c_str()).Release();
67 static jstring GetClientSecret(JNIEnv* env, jclass clazz) {
68 return ConvertUTF8ToJavaString(
69 env, google_apis::GetOAuth2ClientSecret(
70 google_apis::CLIENT_REMOTING).c_str()).Release();
73 static void Connect(JNIEnv* env,
74 jclass clazz,
75 jstring username,
76 jstring authToken,
77 jstring hostJid,
78 jstring hostId,
79 jstring hostPubkey,
80 jstring pairId,
81 jstring pairSecret,
82 jstring capabilities) {
83 remoting::ChromotingJniRuntime::GetInstance()->ConnectToHost(
84 ConvertJavaStringToUTF8(env, username).c_str(),
85 ConvertJavaStringToUTF8(env, authToken).c_str(),
86 ConvertJavaStringToUTF8(env, hostJid).c_str(),
87 ConvertJavaStringToUTF8(env, hostId).c_str(),
88 ConvertJavaStringToUTF8(env, hostPubkey).c_str(),
89 ConvertJavaStringToUTF8(env, pairId).c_str(),
90 ConvertJavaStringToUTF8(env, pairSecret).c_str(),
91 ConvertJavaStringToUTF8(env, capabilities).c_str());
94 static void Disconnect(JNIEnv* env, jclass clazz) {
95 remoting::ChromotingJniRuntime::GetInstance()->DisconnectFromHost();
98 static void AuthenticationResponse(JNIEnv* env,
99 jclass clazz,
100 jstring pin,
101 jboolean createPair,
102 jstring deviceName) {
103 remoting::ChromotingJniRuntime::GetInstance()->session()->ProvideSecret(
104 ConvertJavaStringToUTF8(env, pin).c_str(), createPair,
105 ConvertJavaStringToUTF8(env, deviceName));
108 static void ScheduleRedraw(JNIEnv* env, jclass clazz) {
109 remoting::ChromotingJniRuntime::GetInstance()->session()->RedrawDesktop();
112 static void SendMouseEvent(JNIEnv* env,
113 jclass clazz,
114 jint x,
115 jint y,
116 jint whichButton,
117 jboolean buttonDown) {
118 // Button must be within the bounds of the MouseEvent_MouseButton enum.
119 DCHECK(whichButton >= 0 && whichButton < 5);
121 remoting::ChromotingJniRuntime::GetInstance()->session()->SendMouseEvent(
122 x, y,
123 static_cast<remoting::protocol::MouseEvent_MouseButton>(whichButton),
124 buttonDown);
127 static void SendMouseWheelEvent(JNIEnv* env,
128 jclass clazz,
129 jint delta_x,
130 jint delta_y) {
131 remoting::ChromotingJniRuntime::GetInstance()->session()->SendMouseWheelEvent(
132 delta_x, delta_y);
135 static jboolean SendKeyEvent(JNIEnv* env,
136 jclass clazz,
137 jint keyCode,
138 jboolean keyDown) {
139 return remoting::ChromotingJniRuntime::GetInstance()->session()->SendKeyEvent(
140 keyCode, keyDown);
143 static void SendTextEvent(JNIEnv* env,
144 jclass clazz,
145 jstring text) {
146 remoting::ChromotingJniRuntime::GetInstance()->session()->SendTextEvent(
147 ConvertJavaStringToUTF8(env, text));
150 static void EnableVideoChannel(JNIEnv* env,
151 jclass clazz,
152 jboolean enable) {
153 remoting::ChromotingJniRuntime::GetInstance()->session()->EnableVideoChannel(
154 enable);
157 static void OnThirdPartyTokenFetched(JNIEnv* env,
158 jclass clazz,
159 jstring token,
160 jstring shared_secret) {
161 ChromotingJniRuntime* runtime = remoting::ChromotingJniRuntime::GetInstance();
162 runtime->network_task_runner()->PostTask(FROM_HERE, base::Bind(
163 &ChromotingJniInstance::HandleOnThirdPartyTokenFetched,
164 runtime->session(),
165 ConvertJavaStringToUTF8(env, token),
166 ConvertJavaStringToUTF8(env, shared_secret)));
169 static void SendExtensionMessage(JNIEnv* env,
170 jclass clazz,
171 jstring type,
172 jstring data) {
173 remoting::ChromotingJniRuntime::GetInstance()->session()->SendClientMessage(
174 ConvertJavaStringToUTF8(env, type),
175 ConvertJavaStringToUTF8(env, data));
178 // ChromotingJniRuntime implementation.
180 // static
181 ChromotingJniRuntime* ChromotingJniRuntime::GetInstance() {
182 return Singleton<ChromotingJniRuntime>::get();
185 ChromotingJniRuntime::ChromotingJniRuntime() {
186 // On Android, the UI thread is managed by Java, so we need to attach and
187 // start a special type of message loop to allow Chromium code to run tasks.
188 ui_loop_.reset(new base::MessageLoopForUI());
189 ui_loop_->Start();
191 // TODO(solb) Stop pretending to control the managed UI thread's lifetime.
192 ui_task_runner_ = new AutoThreadTaskRunner(ui_loop_->message_loop_proxy(),
193 base::MessageLoop::QuitClosure());
194 network_task_runner_ = AutoThread::CreateWithType("native_net",
195 ui_task_runner_,
196 base::MessageLoop::TYPE_IO);
197 display_task_runner_ = AutoThread::Create("native_disp",
198 ui_task_runner_);
200 url_requester_ =
201 new URLRequestContextGetter(network_task_runner_, network_task_runner_);
203 // Allows later decoding of video frames.
204 media::InitializeCPUSpecificYUVConversions();
207 ChromotingJniRuntime::~ChromotingJniRuntime() {
208 // The singleton should only ever be destroyed on the main thread.
209 DCHECK(ui_task_runner_->BelongsToCurrentThread());
211 // The session must be shut down first, since it depends on our other
212 // components' still being alive.
213 DisconnectFromHost();
215 base::WaitableEvent done_event(false, false);
216 network_task_runner_->PostTask(FROM_HERE, base::Bind(
217 &ChromotingJniRuntime::DetachFromVmAndSignal,
218 base::Unretained(this),
219 &done_event));
220 done_event.Wait();
221 display_task_runner_->PostTask(FROM_HERE, base::Bind(
222 &ChromotingJniRuntime::DetachFromVmAndSignal,
223 base::Unretained(this),
224 &done_event));
225 done_event.Wait();
226 base::android::LibraryLoaderExitHook();
227 base::android::DetachFromVM();
230 void ChromotingJniRuntime::ConnectToHost(const char* username,
231 const char* auth_token,
232 const char* host_jid,
233 const char* host_id,
234 const char* host_pubkey,
235 const char* pairing_id,
236 const char* pairing_secret,
237 const char* capabilities) {
238 DCHECK(ui_task_runner_->BelongsToCurrentThread());
239 DCHECK(!session_.get());
240 session_ = new ChromotingJniInstance(this,
241 username,
242 auth_token,
243 host_jid,
244 host_id,
245 host_pubkey,
246 pairing_id,
247 pairing_secret,
248 capabilities);
251 void ChromotingJniRuntime::DisconnectFromHost() {
252 DCHECK(ui_task_runner_->BelongsToCurrentThread());
253 if (session_.get()) {
254 session_->Disconnect();
255 session_ = nullptr;
259 void ChromotingJniRuntime::OnConnectionState(
260 protocol::ConnectionToHost::State state,
261 protocol::ErrorCode error) {
262 DCHECK(ui_task_runner_->BelongsToCurrentThread());
264 JNIEnv* env = base::android::AttachCurrentThread();
265 Java_JniInterface_onConnectionState(env, state, error);
268 void ChromotingJniRuntime::DisplayAuthenticationPrompt(bool pairing_supported) {
269 DCHECK(ui_task_runner_->BelongsToCurrentThread());
271 JNIEnv* env = base::android::AttachCurrentThread();
272 Java_JniInterface_displayAuthenticationPrompt(env, pairing_supported);
275 void ChromotingJniRuntime::CommitPairingCredentials(const std::string& host,
276 const std::string& id,
277 const std::string& secret) {
278 DCHECK(ui_task_runner_->BelongsToCurrentThread());
280 JNIEnv* env = base::android::AttachCurrentThread();
281 ScopedJavaLocalRef<jstring> j_host = ConvertUTF8ToJavaString(env, host);
282 ScopedJavaLocalRef<jstring> j_id = ConvertUTF8ToJavaString(env, id);
283 ScopedJavaLocalRef<jstring> j_secret = ConvertUTF8ToJavaString(env,secret);
285 Java_JniInterface_commitPairingCredentials(
286 env, j_host.obj(), j_id.obj(), j_secret.obj());
289 void ChromotingJniRuntime::FetchThirdPartyToken(const GURL& token_url,
290 const std::string& client_id,
291 const std::string& scope) {
292 DCHECK(ui_task_runner_->BelongsToCurrentThread());
293 JNIEnv* env = base::android::AttachCurrentThread();
295 ScopedJavaLocalRef<jstring> j_url =
296 ConvertUTF8ToJavaString(env, token_url.spec());
297 ScopedJavaLocalRef<jstring> j_client_id =
298 ConvertUTF8ToJavaString(env, client_id);
299 ScopedJavaLocalRef<jstring> j_scope = ConvertUTF8ToJavaString(env, scope);
301 Java_JniInterface_fetchThirdPartyToken(
302 env, j_url.obj(), j_client_id.obj(), j_scope.obj());
305 void ChromotingJniRuntime::SetCapabilities(const std::string& capabilities) {
306 DCHECK(ui_task_runner_->BelongsToCurrentThread());
307 JNIEnv* env = base::android::AttachCurrentThread();
309 ScopedJavaLocalRef<jstring> j_cap =
310 ConvertUTF8ToJavaString(env, capabilities);
312 Java_JniInterface_setCapabilities(env, j_cap.obj());
315 void ChromotingJniRuntime::HandleExtensionMessage(const std::string& type,
316 const std::string& message) {
317 DCHECK(ui_task_runner_->BelongsToCurrentThread());
318 JNIEnv* env = base::android::AttachCurrentThread();
320 ScopedJavaLocalRef<jstring> j_type = ConvertUTF8ToJavaString(env, type);
321 ScopedJavaLocalRef<jstring> j_message = ConvertUTF8ToJavaString(env, message);
323 Java_JniInterface_handleExtensionMessage(env, j_type.obj(), j_message.obj());
326 base::android::ScopedJavaLocalRef<jobject> ChromotingJniRuntime::NewBitmap(
327 webrtc::DesktopSize size) {
328 JNIEnv* env = base::android::AttachCurrentThread();
329 return Java_JniInterface_newBitmap(env, size.width(), size.height());
332 void ChromotingJniRuntime::UpdateFrameBitmap(jobject bitmap) {
333 DCHECK(display_task_runner_->BelongsToCurrentThread());
335 JNIEnv* env = base::android::AttachCurrentThread();
336 Java_JniInterface_setVideoFrame(env, bitmap);
339 void ChromotingJniRuntime::UpdateCursorShape(
340 const protocol::CursorShapeInfo& cursor_shape) {
341 DCHECK(display_task_runner_->BelongsToCurrentThread());
343 // const_cast<> is safe as long as the Java updateCursorShape() method copies
344 // the data out of the buffer without mutating it, and doesn't keep any
345 // reference to the buffer afterwards. Unfortunately, there seems to be no way
346 // to create a read-only ByteBuffer from a pointer-to-const.
347 char* data = string_as_array(const_cast<std::string*>(&cursor_shape.data()));
348 int cursor_total_bytes =
349 cursor_shape.width() * cursor_shape.height() * kBytesPerPixel;
351 JNIEnv* env = base::android::AttachCurrentThread();
352 base::android::ScopedJavaLocalRef<jobject> buffer(env,
353 env->NewDirectByteBuffer(data, cursor_total_bytes));
354 Java_JniInterface_updateCursorShape(env,
355 cursor_shape.width(),
356 cursor_shape.height(),
357 cursor_shape.hotspot_x(),
358 cursor_shape.hotspot_y(),
359 buffer.obj());
362 void ChromotingJniRuntime::RedrawCanvas() {
363 DCHECK(display_task_runner_->BelongsToCurrentThread());
365 JNIEnv* env = base::android::AttachCurrentThread();
366 Java_JniInterface_redrawGraphicsInternal(env);
369 void ChromotingJniRuntime::DetachFromVmAndSignal(base::WaitableEvent* waiter) {
370 base::android::DetachFromVM();
371 waiter->Signal();
373 } // namespace remoting