OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "remoting/client/jni/jni_client.h" | 5 #include "remoting/client/jni/jni_client.h" |
6 | 6 |
| 7 #include "base/android/jni_android.h" |
| 8 #include "base/android/jni_string.h" |
| 9 #include "base/logging.h" |
7 #include "jni/Client_jni.h" | 10 #include "jni/Client_jni.h" |
| 11 #include "remoting/client/jni/chromoting_jni_instance.h" |
| 12 #include "remoting/client/jni/chromoting_jni_runtime.h" |
| 13 #include "remoting/client/jni/jni_touch_event_data.h" |
| 14 |
| 15 using base::android::ConvertJavaStringToUTF8; |
| 16 using base::android::ConvertUTF8ToJavaString; |
| 17 |
| 18 namespace { |
| 19 |
| 20 const int kBytesPerPixel = 4; |
| 21 } |
8 | 22 |
9 namespace remoting { | 23 namespace remoting { |
10 | 24 |
11 JniClient::JniClient() { | 25 JniClient::JniClient(jobject java_client) |
| 26 : java_client_(java_client), weak_factory_(this) {} |
| 27 |
| 28 JniClient::~JniClient() { |
| 29 DCHECK(runtime()->ui_task_runner()->BelongsToCurrentThread()); |
12 } | 30 } |
13 | 31 |
14 JniClient::~JniClient() { | 32 void JniClient::ConnectToHost(const std::string& username, |
| 33 const std::string& auth_token, |
| 34 const std::string& host_jid, |
| 35 const std::string& host_id, |
| 36 const std::string& host_pubkey, |
| 37 const std::string& pairing_id, |
| 38 const std::string& pairing_secret, |
| 39 const std::string& capabilities, |
| 40 const std::string& flags) { |
| 41 DCHECK(runtime()->ui_task_runner()->BelongsToCurrentThread()); |
| 42 DCHECK(!session_); |
| 43 session_ = new ChromotingJniInstance( |
| 44 runtime(), this, username, auth_token, host_jid, host_id, host_pubkey, |
| 45 pairing_id, pairing_secret, capabilities, flags); |
| 46 session_->Connect(); |
| 47 } |
| 48 |
| 49 void JniClient::DisconnectFromHost() { |
| 50 DCHECK(runtime()->ui_task_runner()->BelongsToCurrentThread()); |
| 51 if (session_) { |
| 52 session_->Disconnect(); |
| 53 session_ = nullptr; |
| 54 } |
| 55 } |
| 56 |
| 57 void JniClient::OnConnectionState(protocol::ConnectionToHost::State state, |
| 58 protocol::ErrorCode error) { |
| 59 DCHECK(runtime()->ui_task_runner()->BelongsToCurrentThread()); |
| 60 |
| 61 JNIEnv* env = base::android::AttachCurrentThread(); |
| 62 Java_Client_onConnectionState(env, java_client_, state, error); |
| 63 } |
| 64 |
| 65 void JniClient::DisplayAuthenticationPrompt(bool pairing_supported) { |
| 66 DCHECK(runtime()->ui_task_runner()->BelongsToCurrentThread()); |
| 67 |
| 68 JNIEnv* env = base::android::AttachCurrentThread(); |
| 69 Java_Client_displayAuthenticationPrompt(env, java_client_, pairing_supported); |
| 70 } |
| 71 |
| 72 void JniClient::CommitPairingCredentials(const std::string& host, |
| 73 const std::string& id, |
| 74 const std::string& secret) { |
| 75 DCHECK(runtime()->ui_task_runner()->BelongsToCurrentThread()); |
| 76 |
| 77 JNIEnv* env = base::android::AttachCurrentThread(); |
| 78 ScopedJavaLocalRef<jstring> j_host = ConvertUTF8ToJavaString(env, host); |
| 79 ScopedJavaLocalRef<jstring> j_id = ConvertUTF8ToJavaString(env, id); |
| 80 ScopedJavaLocalRef<jstring> j_secret = ConvertUTF8ToJavaString(env, secret); |
| 81 |
| 82 Java_Client_commitPairingCredentials(env, java_client_, j_host.obj(), |
| 83 j_id.obj(), j_secret.obj()); |
| 84 } |
| 85 |
| 86 void JniClient::FetchThirdPartyToken(const std::string& token_url, |
| 87 const std::string& client_id, |
| 88 const std::string& scope) { |
| 89 DCHECK(runtime()->ui_task_runner()->BelongsToCurrentThread()); |
| 90 JNIEnv* env = base::android::AttachCurrentThread(); |
| 91 |
| 92 ScopedJavaLocalRef<jstring> j_url = ConvertUTF8ToJavaString(env, token_url); |
| 93 ScopedJavaLocalRef<jstring> j_client_id = |
| 94 ConvertUTF8ToJavaString(env, client_id); |
| 95 ScopedJavaLocalRef<jstring> j_scope = ConvertUTF8ToJavaString(env, scope); |
| 96 |
| 97 Java_Client_fetchThirdPartyToken(env, java_client_, j_url.obj(), |
| 98 j_client_id.obj(), j_scope.obj()); |
| 99 } |
| 100 |
| 101 void JniClient::SetCapabilities(const std::string& capabilities) { |
| 102 DCHECK(runtime()->ui_task_runner()->BelongsToCurrentThread()); |
| 103 JNIEnv* env = base::android::AttachCurrentThread(); |
| 104 |
| 105 ScopedJavaLocalRef<jstring> j_cap = |
| 106 ConvertUTF8ToJavaString(env, capabilities); |
| 107 |
| 108 Java_Client_setCapabilities(env, java_client_, j_cap.obj()); |
| 109 } |
| 110 |
| 111 void JniClient::HandleExtensionMessage(const std::string& type, |
| 112 const std::string& message) { |
| 113 DCHECK(runtime()->ui_task_runner()->BelongsToCurrentThread()); |
| 114 JNIEnv* env = base::android::AttachCurrentThread(); |
| 115 |
| 116 ScopedJavaLocalRef<jstring> j_type = ConvertUTF8ToJavaString(env, type); |
| 117 ScopedJavaLocalRef<jstring> j_message = ConvertUTF8ToJavaString(env, message); |
| 118 |
| 119 Java_Client_handleExtensionMessage(env, java_client_, j_type.obj(), |
| 120 j_message.obj()); |
| 121 } |
| 122 |
| 123 base::android::ScopedJavaLocalRef<jobject> JniClient::NewBitmap(int width, |
| 124 int height) { |
| 125 JNIEnv* env = base::android::AttachCurrentThread(); |
| 126 return Java_Client_newBitmap(env, width, height); |
| 127 } |
| 128 |
| 129 void JniClient::UpdateFrameBitmap(jobject bitmap) { |
| 130 DCHECK(runtime()->display_task_runner()->BelongsToCurrentThread()); |
| 131 |
| 132 JNIEnv* env = base::android::AttachCurrentThread(); |
| 133 Java_Client_setVideoFrame(env, java_client_, bitmap); |
| 134 } |
| 135 |
| 136 void JniClient::UpdateCursorShape( |
| 137 const protocol::CursorShapeInfo& cursor_shape) { |
| 138 DCHECK(runtime()->display_task_runner()->BelongsToCurrentThread()); |
| 139 |
| 140 // const_cast<> is safe as long as the Java updateCursorShape() method copies |
| 141 // the data out of the buffer without mutating it, and doesn't keep any |
| 142 // reference to the buffer afterwards. Unfortunately, there seems to be no way |
| 143 // to create a read-only ByteBuffer from a pointer-to-const. |
| 144 char* data = string_as_array(const_cast<std::string*>(&cursor_shape.data())); |
| 145 int cursor_total_bytes = |
| 146 cursor_shape.width() * cursor_shape.height() * kBytesPerPixel; |
| 147 |
| 148 JNIEnv* env = base::android::AttachCurrentThread(); |
| 149 base::android::ScopedJavaLocalRef<jobject> buffer( |
| 150 env, env->NewDirectByteBuffer(data, cursor_total_bytes)); |
| 151 Java_Client_updateCursorShape(env, java_client_, cursor_shape.width(), |
| 152 cursor_shape.height(), cursor_shape.hotspot_x(), |
| 153 cursor_shape.hotspot_y(), buffer.obj()); |
| 154 } |
| 155 |
| 156 void JniClient::RedrawCanvas() { |
| 157 DCHECK(runtime()->display_task_runner()->BelongsToCurrentThread()); |
| 158 |
| 159 JNIEnv* env = base::android::AttachCurrentThread(); |
| 160 Java_Client_redrawGraphicsInternal(env, java_client_); |
15 } | 161 } |
16 | 162 |
17 // static | 163 // static |
18 bool JniClient::RegisterJni(JNIEnv* env) { | 164 bool JniClient::RegisterJni(JNIEnv* env) { |
19 return RegisterNativesImpl(env); | 165 return RegisterNativesImpl(env); |
20 } | 166 } |
21 | 167 |
| 168 void JniClient::Connect( |
| 169 JNIEnv* env, |
| 170 const base::android::JavaParamRef<jobject>& caller, |
| 171 const base::android::JavaParamRef<jstring>& username, |
| 172 const base::android::JavaParamRef<jstring>& authToken, |
| 173 const base::android::JavaParamRef<jstring>& hostJid, |
| 174 const base::android::JavaParamRef<jstring>& hostId, |
| 175 const base::android::JavaParamRef<jstring>& hostPubkey, |
| 176 const base::android::JavaParamRef<jstring>& pairId, |
| 177 const base::android::JavaParamRef<jstring>& pairSecret, |
| 178 const base::android::JavaParamRef<jstring>& capabilities, |
| 179 const base::android::JavaParamRef<jstring>& flags) { |
| 180 ConnectToHost(ConvertJavaStringToUTF8(env, username), |
| 181 ConvertJavaStringToUTF8(env, authToken), |
| 182 ConvertJavaStringToUTF8(env, hostJid), |
| 183 ConvertJavaStringToUTF8(env, hostId), |
| 184 ConvertJavaStringToUTF8(env, hostPubkey), |
| 185 ConvertJavaStringToUTF8(env, pairId), |
| 186 ConvertJavaStringToUTF8(env, pairSecret), |
| 187 ConvertJavaStringToUTF8(env, capabilities), |
| 188 ConvertJavaStringToUTF8(env, flags)); |
| 189 } |
| 190 |
| 191 void JniClient::Disconnect(JNIEnv* env, |
| 192 const base::android::JavaParamRef<jobject>& caller) { |
| 193 DisconnectFromHost(); |
| 194 } |
| 195 |
| 196 void JniClient::AuthenticationResponse( |
| 197 JNIEnv* env, |
| 198 const JavaParamRef<jobject>& caller, |
| 199 const JavaParamRef<jstring>& pin, |
| 200 jboolean createPair, |
| 201 const JavaParamRef<jstring>& deviceName) { |
| 202 session_->ProvideSecret(ConvertJavaStringToUTF8(env, pin).c_str(), createPair, |
| 203 ConvertJavaStringToUTF8(env, deviceName)); |
| 204 } |
| 205 |
| 206 void JniClient::ScheduleRedraw( |
| 207 JNIEnv* env, |
| 208 const base::android::JavaParamRef<jobject>& caller) { |
| 209 session_->RedrawDesktop(); |
| 210 } |
| 211 |
| 212 void JniClient::SendMouseEvent( |
| 213 JNIEnv* env, |
| 214 const base::android::JavaParamRef<jobject>& caller, |
| 215 jint x, |
| 216 jint y, |
| 217 jint whichButton, |
| 218 jboolean buttonDown) { |
| 219 // Button must be within the bounds of the MouseEvent_MouseButton enum. |
| 220 DCHECK(whichButton >= 0 && whichButton < 5); |
| 221 |
| 222 session_->SendMouseEvent( |
| 223 x, y, |
| 224 static_cast<remoting::protocol::MouseEvent_MouseButton>(whichButton), |
| 225 buttonDown); |
| 226 } |
| 227 |
| 228 void JniClient::SendMouseWheelEvent( |
| 229 JNIEnv* env, |
| 230 const base::android::JavaParamRef<jobject>& caller, |
| 231 jint delta_x, |
| 232 jint delta_y) { |
| 233 session_->SendMouseWheelEvent(delta_x, delta_y); |
| 234 } |
| 235 |
| 236 jboolean JniClient::SendKeyEvent( |
| 237 JNIEnv* env, |
| 238 const base::android::JavaParamRef<jobject>& caller, |
| 239 jint scanCode, |
| 240 jint keyCode, |
| 241 jboolean keyDown) { |
| 242 return session_->SendKeyEvent(scanCode, keyCode, keyDown); |
| 243 } |
| 244 |
| 245 void JniClient::SendTextEvent( |
| 246 JNIEnv* env, |
| 247 const base::android::JavaParamRef<jobject>& caller, |
| 248 const JavaParamRef<jstring>& text) { |
| 249 session_->SendTextEvent(ConvertJavaStringToUTF8(env, text)); |
| 250 } |
| 251 |
| 252 void JniClient::SendTouchEvent( |
| 253 JNIEnv* env, |
| 254 const base::android::JavaParamRef<jobject>& caller, |
| 255 jint eventType, |
| 256 const JavaParamRef<jobjectArray>& touchEventObjectArray) { |
| 257 protocol::TouchEvent touch_event; |
| 258 touch_event.set_event_type( |
| 259 static_cast<protocol::TouchEvent::TouchEventType>(eventType)); |
| 260 |
| 261 // Iterate over the elements in the object array and transfer the data from |
| 262 // the java object to a native event object. |
| 263 jsize length = env->GetArrayLength(touchEventObjectArray); |
| 264 DCHECK_GE(length, 0); |
| 265 for (jsize i = 0; i < length; ++i) { |
| 266 protocol::TouchEventPoint* touch_point = touch_event.add_touch_points(); |
| 267 |
| 268 ScopedJavaLocalRef<jobject> java_touch_event( |
| 269 env, env->GetObjectArrayElement(touchEventObjectArray, i)); |
| 270 |
| 271 JniTouchEventData::CopyTouchPointData(env, java_touch_event, touch_point); |
| 272 } |
| 273 |
| 274 session_->SendTouchEvent(touch_event); |
| 275 } |
| 276 |
| 277 void JniClient::EnableVideoChannel( |
| 278 JNIEnv* env, |
| 279 const base::android::JavaParamRef<jobject>& caller, |
| 280 jboolean enable) { |
| 281 session_->EnableVideoChannel(enable); |
| 282 } |
| 283 |
| 284 void JniClient::OnThirdPartyTokenFetched( |
| 285 JNIEnv* env, |
| 286 const base::android::JavaParamRef<jobject>& caller, |
| 287 const JavaParamRef<jstring>& token, |
| 288 const JavaParamRef<jstring>& shared_secret) { |
| 289 runtime()->network_task_runner()->PostTask( |
| 290 FROM_HERE, |
| 291 base::Bind(&ChromotingJniInstance::HandleOnThirdPartyTokenFetched, |
| 292 session_, ConvertJavaStringToUTF8(env, token), |
| 293 ConvertJavaStringToUTF8(env, shared_secret))); |
| 294 } |
| 295 |
| 296 void JniClient::SendExtensionMessage( |
| 297 JNIEnv* env, |
| 298 const base::android::JavaParamRef<jobject>& caller, |
| 299 const JavaParamRef<jstring>& type, |
| 300 const JavaParamRef<jstring>& data) { |
| 301 session_->SendClientMessage(ConvertJavaStringToUTF8(env, type), |
| 302 ConvertJavaStringToUTF8(env, data)); |
| 303 } |
| 304 |
22 void JniClient::Destroy(JNIEnv* env, const JavaParamRef<jobject>& caller) { | 305 void JniClient::Destroy(JNIEnv* env, const JavaParamRef<jobject>& caller) { |
| 306 // The session must be shut down first, since it depends on our other |
| 307 // components' still being alive. |
| 308 DisconnectFromHost(); |
| 309 |
| 310 env->DeleteGlobalRef(java_client_); |
23 delete this; | 311 delete this; |
24 } | 312 } |
25 | 313 |
| 314 base::WeakPtr<JniClient> JniClient::GetWeakPtr() { |
| 315 return weak_factory_.GetWeakPtr(); |
| 316 } |
| 317 |
| 318 // static |
| 319 ChromotingJniRuntime* JniClient::runtime() { |
| 320 return ChromotingJniRuntime::GetInstance(); |
| 321 } |
| 322 |
26 static jlong Init(JNIEnv* env, const JavaParamRef<jobject>& caller) { | 323 static jlong Init(JNIEnv* env, const JavaParamRef<jobject>& caller) { |
27 return reinterpret_cast<intptr_t>(new JniClient()); | 324 jobject caller_ref = env->NewGlobalRef(caller); |
| 325 return reinterpret_cast<intptr_t>(new JniClient(caller_ref)); |
28 } | 326 } |
29 | 327 |
30 } // namespace remoting | 328 } // namespace remoting |
OLD | NEW |