| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 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 package org.chromium.chromoting.jni; | 5 package org.chromium.chromoting.jni; |
| 6 | 6 |
| 7 import android.app.Activity; | |
| 8 import android.app.AlertDialog; | |
| 9 import android.content.Context; | 7 import android.content.Context; |
| 10 import android.content.DialogInterface; | |
| 11 import android.content.SharedPreferences; | |
| 12 import android.graphics.Bitmap; | 8 import android.graphics.Bitmap; |
| 13 import android.graphics.Point; | 9 import android.graphics.Point; |
| 14 import android.os.Build; | |
| 15 import android.os.Looper; | 10 import android.os.Looper; |
| 16 import android.util.Log; | 11 import android.util.Log; |
| 17 import android.view.KeyEvent; | |
| 18 import android.view.View; | |
| 19 import android.widget.CheckBox; | |
| 20 import android.widget.TextView; | |
| 21 import android.widget.Toast; | |
| 22 | 12 |
| 23 import org.chromium.base.CalledByNative; | 13 import org.chromium.base.CalledByNative; |
| 24 import org.chromium.base.JNINamespace; | 14 import org.chromium.base.JNINamespace; |
| 25 import org.chromium.chromoting.CapabilityManager; | 15 import org.chromium.chromoting.CapabilityManager; |
| 26 import org.chromium.chromoting.Chromoting; | |
| 27 import org.chromium.chromoting.R; | 16 import org.chromium.chromoting.R; |
| 17 import org.chromium.chromoting.SessionAuthenticator; |
| 28 | 18 |
| 29 import java.nio.ByteBuffer; | 19 import java.nio.ByteBuffer; |
| 30 import java.nio.ByteOrder; | 20 import java.nio.ByteOrder; |
| 31 | 21 |
| 32 /** | 22 /** |
| 33 * Initializes the Chromium remoting library, and provides JNI calls into it. | 23 * Initializes the Chromium remoting library, and provides JNI calls into it. |
| 34 * All interaction with the native code is centralized in this class. | 24 * All interaction with the native code is centralized in this class. |
| 35 */ | 25 */ |
| 36 @JNINamespace("remoting") | 26 @JNINamespace("remoting") |
| 37 public class JniInterface { | 27 public class JniInterface { |
| 38 /* | 28 /* |
| 39 * Library-loading state machine. | 29 * Library-loading state machine. |
| 40 */ | 30 */ |
| 41 /** Whether the library has been loaded. Accessed on the UI thread. */ | 31 /** Whether the library has been loaded. Accessed on the UI thread. */ |
| 42 private static boolean sLoaded = false; | 32 private static boolean sLoaded = false; |
| 43 | 33 |
| 44 /** The application context. Accessed on the UI thread. */ | 34 /** Used for authentication-related UX during connection. Accessed on the UI
thread. */ |
| 45 private static Activity sContext = null; | 35 private static SessionAuthenticator sAuthenticator; |
| 46 | 36 |
| 47 /** Interface used for connection state notifications. */ | 37 /** Interface used for connection state notifications. */ |
| 48 public interface ConnectionListener { | 38 public interface ConnectionListener { |
| 49 /** | 39 /** |
| 50 * This enum must match the C++ enumeration remoting::protocol::Connecti
onToHost::State. | 40 * This enum must match the C++ enumeration remoting::protocol::Connecti
onToHost::State. |
| 51 */ | 41 */ |
| 52 public enum State { | 42 public enum State { |
| 53 INITIALIZING(0), | 43 INITIALIZING(0), |
| 54 CONNECTING(1), | 44 CONNECTING(1), |
| 55 AUTHENTICATED(2), | 45 AUTHENTICATED(2), |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 145 private static Bitmap sCursorBitmap = null; | 135 private static Bitmap sCursorBitmap = null; |
| 146 | 136 |
| 147 /** Capability Manager through which capabilities and extensions are handled
. */ | 137 /** Capability Manager through which capabilities and extensions are handled
. */ |
| 148 private static CapabilityManager sCapabilityManager = CapabilityManager.getI
nstance(); | 138 private static CapabilityManager sCapabilityManager = CapabilityManager.getI
nstance(); |
| 149 | 139 |
| 150 /** | 140 /** |
| 151 * To be called once from the main Activity. Any subsequent calls will updat
e the application | 141 * To be called once from the main Activity. Any subsequent calls will updat
e the application |
| 152 * context, but not reload the library. This is useful e.g. when the activit
y is closed and the | 142 * context, but not reload the library. This is useful e.g. when the activit
y is closed and the |
| 153 * user later wants to return to the application. Called on the UI thread. | 143 * user later wants to return to the application. Called on the UI thread. |
| 154 */ | 144 */ |
| 155 public static void loadLibrary(Activity context) { | 145 public static void loadLibrary(Context context) { |
| 156 sContext = context; | |
| 157 | |
| 158 if (sLoaded) return; | 146 if (sLoaded) return; |
| 159 | 147 |
| 160 System.loadLibrary("remoting_client_jni"); | 148 System.loadLibrary("remoting_client_jni"); |
| 161 | 149 |
| 162 nativeLoadNative(context); | 150 nativeLoadNative(context); |
| 163 sLoaded = true; | 151 sLoaded = true; |
| 164 } | 152 } |
| 165 | 153 |
| 166 /** Performs the native portion of the initialization. */ | 154 /** Performs the native portion of the initialization. */ |
| 167 private static native void nativeLoadNative(Context context); | 155 private static native void nativeLoadNative(Context context); |
| 168 | 156 |
| 169 /* | 157 /* |
| 170 * API/OAuth2 keys access. | 158 * API/OAuth2 keys access. |
| 171 */ | 159 */ |
| 172 public static native String nativeGetApiKey(); | 160 public static native String nativeGetApiKey(); |
| 173 public static native String nativeGetClientId(); | 161 public static native String nativeGetClientId(); |
| 174 public static native String nativeGetClientSecret(); | 162 public static native String nativeGetClientSecret(); |
| 175 | 163 |
| 164 /** Returns whether the client is connected. */ |
| 165 public static boolean isConnected() { |
| 166 return sConnected; |
| 167 } |
| 168 |
| 176 /** Attempts to form a connection to the user-selected host. Called on the U
I thread. */ | 169 /** Attempts to form a connection to the user-selected host. Called on the U
I thread. */ |
| 177 public static void connectToHost(String username, String authToken, | 170 public static void connectToHost(String username, String authToken, |
| 178 String hostJid, String hostId, String hostPubkey, ConnectionListener
listener) { | 171 String hostJid, String hostId, String hostPubkey, ConnectionListener
listener, |
| 172 SessionAuthenticator authenticator) { |
| 179 disconnectFromHost(); | 173 disconnectFromHost(); |
| 180 | 174 |
| 181 sConnectionListener = listener; | 175 sConnectionListener = listener; |
| 182 SharedPreferences prefs = sContext.getPreferences(Activity.MODE_PRIVATE)
; | 176 sAuthenticator = authenticator; |
| 183 nativeConnect(username, authToken, hostJid, hostId, hostPubkey, | 177 nativeConnect(username, authToken, hostJid, hostId, hostPubkey, |
| 184 prefs.getString(hostId + "_id", ""), prefs.getString(hostId + "_
secret", ""), | 178 sAuthenticator.getPairingId(hostId), sAuthenticator.getPairingSe
cret(hostId), |
| 185 sCapabilityManager.getLocalCapabilities()); | 179 sCapabilityManager.getLocalCapabilities()); |
| 186 sConnected = true; | 180 sConnected = true; |
| 187 } | 181 } |
| 188 | 182 |
| 189 /** Performs the native portion of the connection. */ | 183 /** Performs the native portion of the connection. */ |
| 190 private static native void nativeConnect(String username, String authToken,
String hostJid, | 184 private static native void nativeConnect(String username, String authToken,
String hostJid, |
| 191 String hostId, String hostPubkey, String pairId, String pairSecret, | 185 String hostId, String hostPubkey, String pairId, String pairSecret, |
| 192 String capabilities); | 186 String capabilities); |
| 193 | 187 |
| 194 /** Severs the connection and cleans up. Called on the UI thread. */ | 188 /** Severs the connection and cleans up. Called on the UI thread. */ |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 231 if (state == ConnectionListener.State.FAILED || state == ConnectionListe
ner.State.CLOSED) { | 225 if (state == ConnectionListener.State.FAILED || state == ConnectionListe
ner.State.CLOSED) { |
| 232 // Disconnect from the host here, otherwise the next time connectToH
ost() is called, | 226 // Disconnect from the host here, otherwise the next time connectToH
ost() is called, |
| 233 // it will try to disconnect, triggering an incorrect status notific
ation. | 227 // it will try to disconnect, triggering an incorrect status notific
ation. |
| 234 disconnectFromHostWithoutNotification(); | 228 disconnectFromHostWithoutNotification(); |
| 235 } | 229 } |
| 236 } | 230 } |
| 237 | 231 |
| 238 /** Prompts the user to enter a PIN. Called on the UI thread. */ | 232 /** Prompts the user to enter a PIN. Called on the UI thread. */ |
| 239 @CalledByNative | 233 @CalledByNative |
| 240 private static void displayAuthenticationPrompt(boolean pairingSupported) { | 234 private static void displayAuthenticationPrompt(boolean pairingSupported) { |
| 241 AlertDialog.Builder pinPrompt = new AlertDialog.Builder(sContext); | 235 sAuthenticator.displayAuthenticationPrompt(pairingSupported); |
| 242 pinPrompt.setTitle(sContext.getString(R.string.title_authenticate)); | |
| 243 pinPrompt.setMessage(sContext.getString(R.string.pin_message_android)); | |
| 244 pinPrompt.setIcon(android.R.drawable.ic_lock_lock); | |
| 245 | |
| 246 final View pinEntry = sContext.getLayoutInflater().inflate(R.layout.pin_
dialog, null); | |
| 247 pinPrompt.setView(pinEntry); | |
| 248 | |
| 249 final TextView pinTextView = (TextView) pinEntry.findViewById(R.id.pin_d
ialog_text); | |
| 250 final CheckBox pinCheckBox = (CheckBox) pinEntry.findViewById(R.id.pin_d
ialog_check); | |
| 251 | |
| 252 if (!pairingSupported) { | |
| 253 pinCheckBox.setChecked(false); | |
| 254 pinCheckBox.setVisibility(View.GONE); | |
| 255 } | |
| 256 | |
| 257 pinPrompt.setPositiveButton( | |
| 258 R.string.connect_button, new DialogInterface.OnClickListener() { | |
| 259 @Override | |
| 260 public void onClick(DialogInterface dialog, int which) { | |
| 261 Log.i("jniiface", "User provided a PIN code"); | |
| 262 if (sConnected) { | |
| 263 nativeAuthenticationResponse(String.valueOf(pinTextV
iew.getText()), | |
| 264 pinCheckBox.isChecked(), Build.MODEL); | |
| 265 } else { | |
| 266 String message = sContext.getString(R.string.error_n
etwork_error); | |
| 267 Toast.makeText(sContext, message, Toast.LENGTH_LONG)
.show(); | |
| 268 } | |
| 269 } | |
| 270 }); | |
| 271 | |
| 272 pinPrompt.setNegativeButton( | |
| 273 R.string.cancel, new DialogInterface.OnClickListener() { | |
| 274 @Override | |
| 275 public void onClick(DialogInterface dialog, int which) { | |
| 276 Log.i("jniiface", "User canceled pin entry prompt"); | |
| 277 disconnectFromHost(); | |
| 278 } | |
| 279 }); | |
| 280 | |
| 281 final AlertDialog pinDialog = pinPrompt.create(); | |
| 282 | |
| 283 pinTextView.setOnEditorActionListener( | |
| 284 new TextView.OnEditorActionListener() { | |
| 285 @Override | |
| 286 public boolean onEditorAction(TextView v, int actionId, KeyE
vent event) { | |
| 287 // The user pressed enter on the keypad (equivalent to t
he connect button). | |
| 288 pinDialog.getButton(AlertDialog.BUTTON_POSITIVE).perform
Click(); | |
| 289 pinDialog.dismiss(); | |
| 290 return true; | |
| 291 } | |
| 292 }); | |
| 293 | |
| 294 pinDialog.setOnCancelListener( | |
| 295 new DialogInterface.OnCancelListener() { | |
| 296 @Override | |
| 297 public void onCancel(DialogInterface dialog) { | |
| 298 // The user backed out of the dialog (equivalent to the
cancel button). | |
| 299 pinDialog.getButton(AlertDialog.BUTTON_NEGATIVE).perform
Click(); | |
| 300 } | |
| 301 }); | |
| 302 | |
| 303 pinDialog.show(); | |
| 304 } | 236 } |
| 305 | 237 |
| 306 /** | 238 /** |
| 307 * Performs the native response to the user's PIN. | 239 * Performs the native response to the user's PIN. |
| 308 * @param pin The entered PIN. | 240 * @param pin The entered PIN. |
| 309 * @param createPair Whether to create a new pairing for this client. | 241 * @param createPair Whether to create a new pairing for this client. |
| 310 * @param deviceName The device name to appear in the pairing registry. Only
used if createPair | 242 * @param deviceName The device name to appear in the pairing registry. Only
used if createPair |
| 311 * is true. | 243 * is true. |
| 312 */ | 244 */ |
| 245 public static void handleAuthenticationResponse(String pin, boolean createPa
ir, |
| 246 String deviceName) { |
| 247 assert sConnected; |
| 248 nativeAuthenticationResponse(pin, createPair, deviceName); |
| 249 } |
| 250 |
| 251 /** Native implementation of handleAuthenticationResponse(). */ |
| 313 private static native void nativeAuthenticationResponse(String pin, boolean
createPair, | 252 private static native void nativeAuthenticationResponse(String pin, boolean
createPair, |
| 314 String deviceName); | 253 String deviceName); |
| 315 | 254 |
| 316 /** Saves newly-received pairing credentials to permanent storage. Called on
the UI thread. */ | 255 /** Saves newly-received pairing credentials to permanent storage. Called on
the UI thread. */ |
| 317 @CalledByNative | 256 @CalledByNative |
| 318 private static void commitPairingCredentials(String host, String id, String
secret) { | 257 private static void commitPairingCredentials(String host, String id, String
secret) { |
| 319 // Empty |id| indicates that pairing needs to be removed. | 258 sAuthenticator.commitPairingCredentials(host, id, secret); |
| 320 if (id.isEmpty()) { | |
| 321 sContext.getPreferences(Activity.MODE_PRIVATE).edit() | |
| 322 .remove(host + "_id") | |
| 323 .remove(host + "_secret") | |
| 324 .apply(); | |
| 325 } else { | |
| 326 sContext.getPreferences(Activity.MODE_PRIVATE).edit() | |
| 327 .putString(host + "_id", id) | |
| 328 .putString(host + "_secret", secret) | |
| 329 .apply(); | |
| 330 } | |
| 331 } | 259 } |
| 332 | 260 |
| 333 /** | 261 /** |
| 334 * Moves the mouse cursor, possibly while clicking the specified (nonnegativ
e) button. Called | 262 * Moves the mouse cursor, possibly while clicking the specified (nonnegativ
e) button. Called |
| 335 * on the UI thread. | 263 * on the UI thread. |
| 336 */ | 264 */ |
| 337 public static void sendMouseEvent(int x, int y, int whichButton, boolean but
tonDown) { | 265 public static void sendMouseEvent(int x, int y, int whichButton, boolean but
tonDown) { |
| 338 if (!sConnected) { | 266 if (!sConnected) { |
| 339 return; | 267 return; |
| 340 } | 268 } |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 491 return sCursorBitmap; | 419 return sCursorBitmap; |
| 492 } | 420 } |
| 493 | 421 |
| 494 // | 422 // |
| 495 // Third Party Authentication | 423 // Third Party Authentication |
| 496 // | 424 // |
| 497 | 425 |
| 498 /** Pops up a third party login page to fetch the token required for authent
ication. */ | 426 /** Pops up a third party login page to fetch the token required for authent
ication. */ |
| 499 @CalledByNative | 427 @CalledByNative |
| 500 public static void fetchThirdPartyToken(String tokenUrl, String clientId, St
ring scope) { | 428 public static void fetchThirdPartyToken(String tokenUrl, String clientId, St
ring scope) { |
| 501 Chromoting app = (Chromoting) sContext; | 429 sAuthenticator.fetchThirdPartyToken(tokenUrl, clientId, scope); |
| 502 app.fetchThirdPartyToken(tokenUrl, clientId, scope); | |
| 503 } | 430 } |
| 504 | 431 |
| 505 /** | 432 /** |
| 506 * Notify the native code to continue authentication with the |token| and th
e |sharedSecret|. | 433 * Notify the native code to continue authentication with the |token| and th
e |sharedSecret|. |
| 507 */ | 434 */ |
| 508 public static void onThirdPartyTokenFetched(String token, String sharedSecre
t) { | 435 public static void onThirdPartyTokenFetched(String token, String sharedSecre
t) { |
| 509 if (!sConnected) { | 436 if (!sConnected) { |
| 510 return; | 437 return; |
| 511 } | 438 } |
| 512 | 439 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 540 public static void sendExtensionMessage(String type, String data) { | 467 public static void sendExtensionMessage(String type, String data) { |
| 541 if (!sConnected) { | 468 if (!sConnected) { |
| 542 return; | 469 return; |
| 543 } | 470 } |
| 544 | 471 |
| 545 nativeSendExtensionMessage(type, data); | 472 nativeSendExtensionMessage(type, data); |
| 546 } | 473 } |
| 547 | 474 |
| 548 private static native void nativeSendExtensionMessage(String type, String da
ta); | 475 private static native void nativeSendExtensionMessage(String type, String da
ta); |
| 549 } | 476 } |
| OLD | NEW |