Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / remoting / android / java / src / org / chromium / chromoting / jni / JniInterface.java
blob52d1ffdf7c66892ca0c94e94e31008b3299e9b9f
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 package org.chromium.chromoting.jni;
7 import android.content.Context;
8 import android.graphics.Bitmap;
9 import android.graphics.Point;
10 import android.os.Looper;
11 import android.util.Log;
13 import org.chromium.base.annotations.CalledByNative;
14 import org.chromium.base.annotations.JNINamespace;
15 import org.chromium.chromoting.CapabilityManager;
16 import org.chromium.chromoting.R;
17 import org.chromium.chromoting.SessionAuthenticator;
19 import java.nio.ByteBuffer;
20 import java.nio.ByteOrder;
22 /**
23 * Initializes the Chromium remoting library, and provides JNI calls into it.
24 * All interaction with the native code is centralized in this class.
26 @JNINamespace("remoting")
27 public class JniInterface {
29 * Library-loading state machine.
31 /** Whether the library has been loaded. Accessed on the UI thread. */
32 private static boolean sLoaded = false;
34 /** Used for authentication-related UX during connection. Accessed on the UI thread. */
35 private static SessionAuthenticator sAuthenticator;
37 /** Interface used for connection state notifications. */
38 public interface ConnectionListener {
39 /**
40 * This enum must match the C++ enumeration remoting::protocol::ConnectionToHost::State.
42 public enum State {
43 INITIALIZING(0),
44 CONNECTING(1),
45 AUTHENTICATED(2),
46 CONNECTED(3),
47 FAILED(4),
48 CLOSED(5);
50 private final int mValue;
52 State(int value) {
53 mValue = value;
56 public int value() {
57 return mValue;
60 public static State fromValue(int value) {
61 return values()[value];
65 /**
66 * This enum must match the C++ enumeration remoting::protocol::ErrorCode.
68 public enum Error {
69 OK(0, 0),
70 PEER_IS_OFFLINE(1, R.string.error_host_is_offline),
71 SESSION_REJECTED(2, R.string.error_invalid_access_code),
72 INCOMPATIBLE_PROTOCOL(3, R.string.error_incompatible_protocol),
73 AUTHENTICATION_FAILED(4, R.string.error_invalid_access_code),
74 CHANNEL_CONNECTION_ERROR(5, R.string.error_p2p_failure),
75 SIGNALING_ERROR(6, R.string.error_p2p_failure),
76 SIGNALING_TIMEOUT(7, R.string.error_p2p_failure),
77 HOST_OVERLOAD(8, R.string.error_host_overload),
78 UNKNOWN_ERROR(9, R.string.error_unexpected);
80 private final int mValue;
81 private final int mMessage;
83 Error(int value, int message) {
84 mValue = value;
85 mMessage = message;
88 public int value() {
89 return mValue;
92 public int message() {
93 return mMessage;
96 public static Error fromValue(int value) {
97 return values()[value];
103 * Notified on connection state change.
104 * @param state The new connection state.
105 * @param error The error code, if state is STATE_FAILED.
107 void onConnectionState(State state, Error error);
111 * Connection-initiating state machine.
113 /** Whether the native code is attempting a connection. Accessed on the UI thread. */
114 private static boolean sConnected = false;
116 /** Notified upon successful connection or disconnection. Accessed on the UI thread. */
117 private static ConnectionListener sConnectionListener = null;
120 * Callback invoked on the graphics thread to repaint the desktop. Accessed on the UI and
121 * graphics threads.
123 private static Runnable sRedrawCallback = null;
125 /** Bitmap holding a copy of the latest video frame. Accessed on the UI and graphics threads. */
126 private static Bitmap sFrameBitmap = null;
128 /** Protects access to sFrameBitmap. */
129 private static final Object sFrameLock = new Object();
131 /** Position of cursor hot-spot. Accessed on the graphics thread. */
132 private static Point sCursorHotspot = new Point();
134 /** Bitmap holding the cursor shape. Accessed on the graphics thread. */
135 private static Bitmap sCursorBitmap = null;
137 /** Capability Manager through which capabilities and extensions are handled. */
138 private static CapabilityManager sCapabilityManager = CapabilityManager.getInstance();
141 * To be called once from the main Activity. Any subsequent calls will update the application
142 * context, but not reload the library. This is useful e.g. when the activity is closed and the
143 * user later wants to return to the application. Called on the UI thread.
145 public static void loadLibrary(Context context) {
146 if (sLoaded) return;
148 System.loadLibrary("remoting_client_jni");
150 nativeLoadNative(context);
151 sLoaded = true;
154 /** Performs the native portion of the initialization. */
155 private static native void nativeLoadNative(Context context);
158 * API/OAuth2 keys access.
160 public static native String nativeGetApiKey();
161 public static native String nativeGetClientId();
162 public static native String nativeGetClientSecret();
164 /** Returns whether the client is connected. */
165 public static boolean isConnected() {
166 return sConnected;
169 /** Attempts to form a connection to the user-selected host. Called on the UI thread. */
170 public static void connectToHost(String username, String authToken,
171 String hostJid, String hostId, String hostPubkey, ConnectionListener listener,
172 SessionAuthenticator authenticator) {
173 disconnectFromHost();
175 sConnectionListener = listener;
176 sAuthenticator = authenticator;
177 nativeConnect(username, authToken, hostJid, hostId, hostPubkey,
178 sAuthenticator.getPairingId(hostId), sAuthenticator.getPairingSecret(hostId),
179 sCapabilityManager.getLocalCapabilities());
180 sConnected = true;
183 /** Performs the native portion of the connection. */
184 private static native void nativeConnect(String username, String authToken, String hostJid,
185 String hostId, String hostPubkey, String pairId, String pairSecret,
186 String capabilities);
188 /** Severs the connection and cleans up. Called on the UI thread. */
189 public static void disconnectFromHost() {
190 if (!sConnected) {
191 return;
194 sConnectionListener.onConnectionState(ConnectionListener.State.CLOSED,
195 ConnectionListener.Error.OK);
197 disconnectFromHostWithoutNotification();
200 /** Same as disconnectFromHost() but without notifying the ConnectionListener. */
201 private static void disconnectFromHostWithoutNotification() {
202 if (!sConnected) {
203 return;
206 nativeDisconnect();
207 sConnectionListener = null;
208 sConnected = false;
210 // Drop the reference to free the Bitmap for GC.
211 synchronized (sFrameLock) {
212 sFrameBitmap = null;
216 /** Performs the native portion of the cleanup. */
217 private static native void nativeDisconnect();
219 /** Called by native code whenever the connection status changes. Called on the UI thread. */
220 @CalledByNative
221 private static void onConnectionState(int stateCode, int errorCode) {
222 ConnectionListener.State state = ConnectionListener.State.fromValue(stateCode);
223 ConnectionListener.Error error = ConnectionListener.Error.fromValue(errorCode);
224 sConnectionListener.onConnectionState(state, error);
225 if (state == ConnectionListener.State.FAILED || state == ConnectionListener.State.CLOSED) {
226 // Disconnect from the host here, otherwise the next time connectToHost() is called,
227 // it will try to disconnect, triggering an incorrect status notification.
228 disconnectFromHostWithoutNotification();
232 /** Prompts the user to enter a PIN. Called on the UI thread. */
233 @CalledByNative
234 private static void displayAuthenticationPrompt(boolean pairingSupported) {
235 sAuthenticator.displayAuthenticationPrompt(pairingSupported);
239 * Performs the native response to the user's PIN.
240 * @param pin The entered PIN.
241 * @param createPair Whether to create a new pairing for this client.
242 * @param deviceName The device name to appear in the pairing registry. Only used if createPair
243 * is true.
245 public static void handleAuthenticationResponse(String pin, boolean createPair,
246 String deviceName) {
247 assert sConnected;
248 nativeAuthenticationResponse(pin, createPair, deviceName);
251 /** Native implementation of handleAuthenticationResponse(). */
252 private static native void nativeAuthenticationResponse(String pin, boolean createPair,
253 String deviceName);
255 /** Saves newly-received pairing credentials to permanent storage. Called on the UI thread. */
256 @CalledByNative
257 private static void commitPairingCredentials(String host, String id, String secret) {
258 sAuthenticator.commitPairingCredentials(host, id, secret);
262 * Moves the mouse cursor, possibly while clicking the specified (nonnegative) button. Called
263 * on the UI thread.
265 public static void sendMouseEvent(int x, int y, int whichButton, boolean buttonDown) {
266 if (!sConnected) {
267 return;
270 nativeSendMouseEvent(x, y, whichButton, buttonDown);
273 /** Passes mouse information to the native handling code. */
274 private static native void nativeSendMouseEvent(int x, int y, int whichButton,
275 boolean buttonDown);
277 /** Injects a mouse-wheel event with delta values. Called on the UI thread. */
278 public static void sendMouseWheelEvent(int deltaX, int deltaY) {
279 if (!sConnected) {
280 return;
283 nativeSendMouseWheelEvent(deltaX, deltaY);
286 /** Passes mouse-wheel information to the native handling code. */
287 private static native void nativeSendMouseWheelEvent(int deltaX, int deltaY);
290 * Presses or releases the specified (nonnegative) key. Called on the UI thread. If scanCode
291 * is not zero then keyCode is ignored.
293 public static boolean sendKeyEvent(int scanCode, int keyCode, boolean keyDown) {
294 if (!sConnected) {
295 return false;
298 return nativeSendKeyEvent(scanCode, keyCode, keyDown);
302 * Passes key press information to the native handling code.
304 private static native boolean nativeSendKeyEvent(int scanCode, int keyCode, boolean keyDown);
306 /** Sends TextEvent to the host. Called on the UI thread. */
307 public static void sendTextEvent(String text) {
308 if (!sConnected) {
309 return;
312 nativeSendTextEvent(text);
315 /** Passes text event information to the native handling code. */
316 private static native void nativeSendTextEvent(String text);
319 * Enables or disables the video channel. Called on the UI thread in response to Activity
320 * lifecycle events.
322 public static void enableVideoChannel(boolean enable) {
323 if (!sConnected) {
324 return;
327 nativeEnableVideoChannel(enable);
330 /** Native implementation of enableVideoChannel() */
331 private static native void nativeEnableVideoChannel(boolean enable);
334 * Sets the redraw callback to the provided functor. Provide a value of null whenever the
335 * window is no longer visible so that we don't continue to draw onto it. Called on the UI
336 * thread.
338 public static void provideRedrawCallback(Runnable redrawCallback) {
339 sRedrawCallback = redrawCallback;
342 /** Forces the native graphics thread to redraw to the canvas. Called on the UI thread. */
343 public static boolean redrawGraphics() {
344 if (!sConnected || sRedrawCallback == null) return false;
346 nativeScheduleRedraw();
347 return true;
350 /** Schedules a redraw on the native graphics thread. */
351 private static native void nativeScheduleRedraw();
354 * Performs the redrawing callback. This is a no-op if the window isn't visible. Called on the
355 * graphics thread.
357 @CalledByNative
358 private static void redrawGraphicsInternal() {
359 Runnable callback = sRedrawCallback;
360 if (callback != null) {
361 callback.run();
366 * Returns a bitmap of the latest video frame. Called on the native graphics thread when
367 * DesktopView is repainted.
369 public static Bitmap getVideoFrame() {
370 if (Looper.myLooper() == Looper.getMainLooper()) {
371 Log.w("jniiface", "Canvas being redrawn on UI thread");
374 synchronized (sFrameLock) {
375 return sFrameBitmap;
380 * Sets a new video frame. Called on the native graphics thread when a new frame is allocated.
382 @CalledByNative
383 private static void setVideoFrame(Bitmap bitmap) {
384 if (Looper.myLooper() == Looper.getMainLooper()) {
385 Log.w("jniiface", "Video frame updated on UI thread");
388 synchronized (sFrameLock) {
389 sFrameBitmap = bitmap;
394 * Creates a new Bitmap to hold video frame pixels. Called by native code which stores a global
395 * reference to the Bitmap and writes the decoded frame pixels to it.
397 @CalledByNative
398 private static Bitmap newBitmap(int width, int height) {
399 return Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
403 * Updates the cursor shape. This is called on the graphics thread when receiving a new cursor
404 * shape from the host.
406 @CalledByNative
407 public static void updateCursorShape(int width, int height, int hotspotX, int hotspotY,
408 ByteBuffer buffer) {
409 sCursorHotspot = new Point(hotspotX, hotspotY);
411 int[] data = new int[width * height];
412 buffer.order(ByteOrder.LITTLE_ENDIAN);
413 buffer.asIntBuffer().get(data, 0, data.length);
414 sCursorBitmap = Bitmap.createBitmap(data, width, height, Bitmap.Config.ARGB_8888);
417 /** Position of cursor hotspot within cursor image. Called on the graphics thread. */
418 public static Point getCursorHotspot() {
419 return sCursorHotspot;
422 /** Returns the current cursor shape. Called on the graphics thread. */
423 public static Bitmap getCursorBitmap() {
424 return sCursorBitmap;
428 // Third Party Authentication
431 /** Pops up a third party login page to fetch the token required for authentication. */
432 @CalledByNative
433 public static void fetchThirdPartyToken(String tokenUrl, String clientId, String scope) {
434 sAuthenticator.fetchThirdPartyToken(tokenUrl, clientId, scope);
438 * Notify the native code to continue authentication with the |token| and the |sharedSecret|.
440 public static void onThirdPartyTokenFetched(String token, String sharedSecret) {
441 if (!sConnected) {
442 return;
445 nativeOnThirdPartyTokenFetched(token, sharedSecret);
448 /** Passes authentication data to the native handling code. */
449 private static native void nativeOnThirdPartyTokenFetched(String token, String sharedSecret);
452 // Host and Client Capabilities
455 /** Set the list of negotiated capabilities between host and client. Called on the UI thread. */
456 @CalledByNative
457 public static void setCapabilities(String capabilities) {
458 sCapabilityManager.setNegotiatedCapabilities(capabilities);
462 // Extension Message Handling
465 /** Passes on the deconstructed ExtensionMessage to the app. Called on the UI thread. */
466 @CalledByNative
467 public static void handleExtensionMessage(String type, String data) {
468 sCapabilityManager.onExtensionMessage(type, data);
471 /** Sends an extension message to the Chromoting host. Called on the UI thread. */
472 public static void sendExtensionMessage(String type, String data) {
473 if (!sConnected) {
474 return;
477 nativeSendExtensionMessage(type, data);
480 private static native void nativeSendExtensionMessage(String type, String data);