Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / remoting / android / java / src / org / chromium / chromoting / jni / JniInterface.java
blob7057179b99ec94f8a764a7dc9cf00f8419742d5b
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.CalledByNative;
14 import org.chromium.base.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);
289 /** Presses or releases the specified (nonnegative) key. Called on the UI thread. */
290 public static boolean sendKeyEvent(int keyCode, boolean keyDown) {
291 if (!sConnected) {
292 return false;
295 return nativeSendKeyEvent(keyCode, keyDown);
298 /** Passes key press information to the native handling code. */
299 private static native boolean nativeSendKeyEvent(int keyCode, boolean keyDown);
301 /** Sends TextEvent to the host. Called on the UI thread. */
302 public static void sendTextEvent(String text) {
303 if (!sConnected) {
304 return;
307 nativeSendTextEvent(text);
310 /** Passes text event information to the native handling code. */
311 private static native void nativeSendTextEvent(String text);
314 * Enables or disables the video channel. Called on the UI thread in response to Activity
315 * lifecycle events.
317 public static void enableVideoChannel(boolean enable) {
318 if (!sConnected) {
319 return;
322 nativeEnableVideoChannel(enable);
325 /** Native implementation of enableVideoChannel() */
326 private static native void nativeEnableVideoChannel(boolean enable);
329 * Sets the redraw callback to the provided functor. Provide a value of null whenever the
330 * window is no longer visible so that we don't continue to draw onto it. Called on the UI
331 * thread.
333 public static void provideRedrawCallback(Runnable redrawCallback) {
334 sRedrawCallback = redrawCallback;
337 /** Forces the native graphics thread to redraw to the canvas. Called on the UI thread. */
338 public static boolean redrawGraphics() {
339 if (!sConnected || sRedrawCallback == null) return false;
341 nativeScheduleRedraw();
342 return true;
345 /** Schedules a redraw on the native graphics thread. */
346 private static native void nativeScheduleRedraw();
349 * Performs the redrawing callback. This is a no-op if the window isn't visible. Called on the
350 * graphics thread.
352 @CalledByNative
353 private static void redrawGraphicsInternal() {
354 Runnable callback = sRedrawCallback;
355 if (callback != null) {
356 callback.run();
361 * Returns a bitmap of the latest video frame. Called on the native graphics thread when
362 * DesktopView is repainted.
364 public static Bitmap getVideoFrame() {
365 if (Looper.myLooper() == Looper.getMainLooper()) {
366 Log.w("jniiface", "Canvas being redrawn on UI thread");
369 synchronized (sFrameLock) {
370 return sFrameBitmap;
375 * Sets a new video frame. Called on the native graphics thread when a new frame is allocated.
377 @CalledByNative
378 private static void setVideoFrame(Bitmap bitmap) {
379 if (Looper.myLooper() == Looper.getMainLooper()) {
380 Log.w("jniiface", "Video frame updated on UI thread");
383 synchronized (sFrameLock) {
384 sFrameBitmap = bitmap;
389 * Creates a new Bitmap to hold video frame pixels. Called by native code which stores a global
390 * reference to the Bitmap and writes the decoded frame pixels to it.
392 @CalledByNative
393 private static Bitmap newBitmap(int width, int height) {
394 return Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
398 * Updates the cursor shape. This is called on the graphics thread when receiving a new cursor
399 * shape from the host.
401 @CalledByNative
402 public static void updateCursorShape(int width, int height, int hotspotX, int hotspotY,
403 ByteBuffer buffer) {
404 sCursorHotspot = new Point(hotspotX, hotspotY);
406 int[] data = new int[width * height];
407 buffer.order(ByteOrder.LITTLE_ENDIAN);
408 buffer.asIntBuffer().get(data, 0, data.length);
409 sCursorBitmap = Bitmap.createBitmap(data, width, height, Bitmap.Config.ARGB_8888);
412 /** Position of cursor hotspot within cursor image. Called on the graphics thread. */
413 public static Point getCursorHotspot() {
414 return sCursorHotspot;
417 /** Returns the current cursor shape. Called on the graphics thread. */
418 public static Bitmap getCursorBitmap() {
419 return sCursorBitmap;
423 // Third Party Authentication
426 /** Pops up a third party login page to fetch the token required for authentication. */
427 @CalledByNative
428 public static void fetchThirdPartyToken(String tokenUrl, String clientId, String scope) {
429 sAuthenticator.fetchThirdPartyToken(tokenUrl, clientId, scope);
433 * Notify the native code to continue authentication with the |token| and the |sharedSecret|.
435 public static void onThirdPartyTokenFetched(String token, String sharedSecret) {
436 if (!sConnected) {
437 return;
440 nativeOnThirdPartyTokenFetched(token, sharedSecret);
443 /** Passes authentication data to the native handling code. */
444 private static native void nativeOnThirdPartyTokenFetched(String token, String sharedSecret);
447 // Host and Client Capabilities
450 /** Set the list of negotiated capabilities between host and client. Called on the UI thread. */
451 @CalledByNative
452 public static void setCapabilities(String capabilities) {
453 sCapabilityManager.setNegotiatedCapabilities(capabilities);
457 // Extension Message Handling
460 /** Passes on the deconstructed ExtensionMessage to the app. Called on the UI thread. */
461 @CalledByNative
462 public static void handleExtensionMessage(String type, String data) {
463 sCapabilityManager.onExtensionMessage(type, data);
466 /** Sends an extension message to the Chromoting host. Called on the UI thread. */
467 public static void sendExtensionMessage(String type, String data) {
468 if (!sConnected) {
469 return;
472 nativeSendExtensionMessage(type, data);
475 private static native void nativeSendExtensionMessage(String type, String data);