EMMA Coverage Report (generated Fri Aug 23 16:39:17 PDT 2013)
[all classes][org.chromium.chromoting.jni]

COVERAGE SUMMARY FOR SOURCE FILE [JniInterface.java]

nameclass, %method, %block, %line, %
JniInterface.java0%   (0/6)0%   (0/26)0%   (0/543)0%   (0/122)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class JniInterface0%   (0/1)0%   (0/16)0%   (0/466)0%   (0/102)
<static initializer> 0%   (0/1)0%   (0/19)0%   (0/9)
JniInterface (): void 0%   (0/1)0%   (0/3)0%   (0/1)
access$000 (String, boolean): void 0%   (0/1)0%   (0/4)0%   (0/1)
access$100 (): Activity 0%   (0/1)0%   (0/2)0%   (0/1)
commitPairingCredentials (String, byte [], byte []): void 0%   (0/1)0%   (0/44)0%   (0/4)
connectToHost (String, String, String, String, String, Runnable): void 0%   (0/1)0%   (0/57)0%   (0/10)
disconnectFromHost (): void 0%   (0/1)0%   (0/31)0%   (0/10)
displayAuthenticationPrompt (boolean): void 0%   (0/1)0%   (0/83)0%   (0/18)
keyboardAction (int, boolean): void 0%   (0/1)0%   (0/7)0%   (0/4)
loadLibrary (Activity): void 0%   (0/1)0%   (0/26)0%   (0/8)
mouseAction (int, int, int, boolean): void 0%   (0/1)0%   (0/9)0%   (0/4)
provideRedrawCallback (Runnable): void 0%   (0/1)0%   (0/3)0%   (0/2)
redrawGraphics (): boolean 0%   (0/1)0%   (0/23)0%   (0/5)
redrawGraphicsInternal (): void 0%   (0/1)0%   (0/5)0%   (0/3)
reportConnectionStatus (int, int): void 0%   (0/1)0%   (0/114)0%   (0/16)
retrieveVideoFrame (): Bitmap 0%   (0/1)0%   (0/36)0%   (0/8)
     
class JniInterface$10%   (0/1)0%   (0/2)0%   (0/9)0%   (0/4)
JniInterface$1 (): void 0%   (0/1)0%   (0/3)0%   (0/1)
onCancel (DialogInterface): void 0%   (0/1)0%   (0/6)0%   (0/3)
     
class JniInterface$20%   (0/1)0%   (0/2)0%   (0/22)0%   (0/4)
JniInterface$2 (TextView, CheckBox): void 0%   (0/1)0%   (0/9)0%   (0/1)
onClick (DialogInterface, int): void 0%   (0/1)0%   (0/13)0%   (0/3)
     
class JniInterface$30%   (0/1)0%   (0/2)0%   (0/16)0%   (0/5)
JniInterface$3 (): void 0%   (0/1)0%   (0/3)0%   (0/1)
onClick (DialogInterface, int): void 0%   (0/1)0%   (0/13)0%   (0/4)
     
class JniInterface$40%   (0/1)0%   (0/2)0%   (0/17)0%   (0/4)
JniInterface$4 (AlertDialog): void 0%   (0/1)0%   (0/6)0%   (0/1)
onEditorAction (TextView, int, KeyEvent): boolean 0%   (0/1)0%   (0/11)0%   (0/3)
     
class JniInterface$50%   (0/1)0%   (0/2)0%   (0/13)0%   (0/3)
JniInterface$5 (AlertDialog): void 0%   (0/1)0%   (0/6)0%   (0/1)
onCancel (DialogInterface): void 0%   (0/1)0%   (0/7)0%   (0/2)

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.
4 
5package org.chromium.chromoting.jni;
6 
7import android.app.Activity;
8import android.app.AlertDialog;
9import android.app.ProgressDialog;
10import android.content.Context;
11import android.content.DialogInterface;
12import android.content.SharedPreferences;
13import android.graphics.Bitmap;
14import android.os.Looper;
15import android.text.InputType;
16import android.util.Log;
17import android.view.KeyEvent;
18import android.view.View;
19import android.view.inputmethod.EditorInfo;
20import android.widget.CheckBox;
21import android.widget.TextView;
22import android.widget.Toast;
23 
24import org.chromium.chromoting.R;
25 
26import java.nio.ByteBuffer;
27import java.nio.ByteOrder;
28 
29/**
30 * Initializes the Chromium remoting library, and provides JNI calls into it.
31 * All interaction with the native code is centralized in this class.
32 */
33public class JniInterface {
34    /** The status code indicating successful connection. */
35    private static final int SUCCESSFUL_CONNECTION = 3;
36 
37    /** The application context. */
38    private static Activity sContext = null;
39 
40    /*
41     * Library-loading state machine.
42     */
43    /** Whether we've already loaded the library. */
44    private static boolean sLoaded = false;
45 
46    /**
47     * To be called once from the main Activity. Any subsequent calls will update the application
48     * context, but not reload the library. This is useful e.g. when the activity is closed and the
49     * user later wants to return to the application.
50     */
51    public static void loadLibrary(Activity context) {
52        sContext = context;
53 
54        synchronized(JniInterface.class) {
55            if (sLoaded) return;
56        }
57 
58        System.loadLibrary("remoting_client_jni");
59        loadNative(context);
60        sLoaded = true;
61    }
62 
63    /** Performs the native portion of the initialization. */
64    private static native void loadNative(Context context);
65 
66    /*
67     * API/OAuth2 keys access.
68     */
69    public static native String getApiKey();
70    public static native String getClientId();
71    public static native String getClientSecret();
72 
73    /*
74     * Connection-initiating state machine.
75     */
76    /** Whether the native code is attempting a connection. */
77    private static boolean sConnected = false;
78 
79    /** Callback to signal upon successful connection. */
80    private static Runnable sSuccessCallback = null;
81 
82    /** Dialog for reporting connection progress. */
83    private static ProgressDialog sProgressIndicator = null;
84 
85    /** Attempts to form a connection to the user-selected host. */
86    public static void connectToHost(String username, String authToken,
87            String hostJid, String hostId, String hostPubkey, Runnable successCallback) {
88        synchronized(JniInterface.class) {
89            if (!sLoaded) return;
90 
91            if (sConnected) {
92                disconnectFromHost();
93            }
94        }
95 
96        sSuccessCallback = successCallback;
97        SharedPreferences prefs = sContext.getPreferences(Activity.MODE_PRIVATE);
98        connectNative(username, authToken, hostJid, hostId, hostPubkey,
99                prefs.getString(hostId + "_id", ""), prefs.getString(hostId + "_secret", ""));
100        sConnected = true;
101    }
102 
103    /** Severs the connection and cleans up. */
104    public static void disconnectFromHost() {
105        synchronized(JniInterface.class) {
106            if (!sLoaded || !sConnected) return;
107 
108            if (sProgressIndicator != null) {
109                sProgressIndicator.dismiss();
110                sProgressIndicator = null;
111            }
112        }
113 
114        disconnectNative();
115        sSuccessCallback = null;
116        sConnected = false;
117    }
118 
119    /** Performs the native portion of the connection. */
120    private static native void connectNative(String username, String authToken, String hostJid,
121            String hostId, String hostPubkey, String pairId, String pairSecret);
122 
123    /** Performs the native portion of the cleanup. */
124    private static native void disconnectNative();
125 
126    /*
127     * Entry points *from* the native code.
128     */
129    /** Callback to signal whenever we need to redraw. */
130    private static Runnable sRedrawCallback = null;
131 
132    /** Screen width of the video feed. */
133    private static int sWidth = 0;
134 
135    /** Screen height of the video feed. */
136    private static int sHeight = 0;
137 
138    /** Buffer holding the video feed. */
139    private static ByteBuffer sBuffer = null;
140 
141    /** Reports whenever the connection status changes. */
142    private static void reportConnectionStatus(int state, int error) {
143        if (state < SUCCESSFUL_CONNECTION && error == 0) {
144            // The connection is still being established, so we'll report the current progress.
145            synchronized (JniInterface.class) {
146                if (sProgressIndicator == null) {
147                    sProgressIndicator = ProgressDialog.show(sContext, sContext.
148                            getString(R.string.progress_title), sContext.getResources().
149                            getStringArray(R.array.protoc_states)[state], true, true,
150                            new DialogInterface.OnCancelListener() {
151                                @Override
152                                public void onCancel(DialogInterface dialog) {
153                                    Log.i("jniiface", "User canceled connection initiation");
154                                    disconnectFromHost();
155                                }
156                            });
157                }
158                else {
159                    sProgressIndicator.setMessage(
160                            sContext.getResources().getStringArray(R.array.protoc_states)[state]);
161                }
162            }
163        }
164        else {
165            // The connection is complete or has failed, so we can lose the progress indicator.
166            synchronized (JniInterface.class) {
167                if (sProgressIndicator != null) {
168                    sProgressIndicator.dismiss();
169                    sProgressIndicator = null;
170                }
171            }
172 
173            if (state == SUCCESSFUL_CONNECTION) {
174                Toast.makeText(sContext, sContext.getResources().
175                        getStringArray(R.array.protoc_states)[state], Toast.LENGTH_SHORT).show();
176 
177                // Actually display the remote desktop.
178                sSuccessCallback.run();
179            } else {
180                Toast.makeText(sContext, sContext.getResources().getStringArray(
181                        R.array.protoc_states)[state] + (error == 0 ? "" : ": " +
182                        sContext.getResources().getStringArray(R.array.protoc_errors)[error]),
183                        Toast.LENGTH_LONG).show();
184            }
185        }
186    }
187 
188    /** Prompts the user to enter a PIN. */
189    private static void displayAuthenticationPrompt(boolean pairingSupported) {
190        AlertDialog.Builder pinPrompt = new AlertDialog.Builder(sContext);
191        pinPrompt.setTitle(sContext.getString(R.string.pin_entry_title));
192        pinPrompt.setMessage(sContext.getString(R.string.pin_entry_message));
193        pinPrompt.setIcon(android.R.drawable.ic_lock_lock);
194 
195        final View pinEntry = sContext.getLayoutInflater().inflate(R.layout.pin_dialog, null);
196        pinPrompt.setView(pinEntry);
197 
198        final TextView pinTextView = (TextView)pinEntry.findViewById(R.id.pin_dialog_text);
199        final CheckBox pinCheckBox = (CheckBox)pinEntry.findViewById(R.id.pin_dialog_check);
200 
201        if (!pairingSupported) {
202            pinCheckBox.setChecked(false);
203            pinCheckBox.setVisibility(View.GONE);
204        }
205 
206        pinPrompt.setPositiveButton(
207                R.string.pin_entry_connect, new DialogInterface.OnClickListener() {
208                    @Override
209                    public void onClick(DialogInterface dialog, int which) {
210                        Log.i("jniiface", "User provided a PIN code");
211                        authenticationResponse(String.valueOf(pinTextView.getText()),
212                                               pinCheckBox.isChecked());
213                    }
214                });
215 
216        pinPrompt.setNegativeButton(
217                R.string.pin_entry_cancel, new DialogInterface.OnClickListener() {
218                    @Override
219                    public void onClick(DialogInterface dialog, int which) {
220                        Log.i("jniiface", "User canceled pin entry prompt");
221                        Toast.makeText(sContext,
222                                sContext.getString(R.string.msg_pin_canceled),
223                                Toast.LENGTH_LONG).show();
224                        disconnectFromHost();
225                    }
226                });
227 
228        final AlertDialog pinDialog = pinPrompt.create();
229 
230        pinTextView.setOnEditorActionListener(
231                new TextView.OnEditorActionListener() {
232                    @Override
233                    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
234                        // The user pressed enter on the keypad (equivalent to the connect button).
235                        pinDialog.getButton(AlertDialog.BUTTON_POSITIVE).performClick();
236                        pinDialog.dismiss();
237                        return true;
238                    }
239                });
240 
241        pinDialog.setOnCancelListener(
242                new DialogInterface.OnCancelListener() {
243                    @Override
244                    public void onCancel(DialogInterface dialog) {
245                        // The user backed out of the dialog (equivalent to the cancel button).
246                        pinDialog.getButton(AlertDialog.BUTTON_NEGATIVE).performClick();
247                    }
248                });
249 
250        pinDialog.show();
251    }
252 
253    /** Saves newly-received pairing credentials to permanent storage. */
254    private static void commitPairingCredentials(String host, byte[] id, byte[] secret) {
255        synchronized (sContext) {
256            sContext.getPreferences(Activity.MODE_PRIVATE).edit().
257                    putString(host + "_id", new String(id)).
258                    putString(host + "_secret", new String(secret)).
259                    apply();
260        }
261    }
262 
263    /**
264     * Sets the redraw callback to the provided functor. Provide a value of null whenever the
265     * window is no longer visible so that we don't continue to draw onto it.
266     */
267    public static void provideRedrawCallback(Runnable redrawCallback) {
268        sRedrawCallback = redrawCallback;
269    }
270 
271    /** Forces the native graphics thread to redraw to the canvas. */
272    public static boolean redrawGraphics() {
273        synchronized(JniInterface.class) {
274            if (!sConnected || sRedrawCallback == null) return false;
275        }
276 
277        scheduleRedrawNative();
278        return true;
279    }
280 
281    /** Performs the redrawing callback. This is a no-op if the window isn't visible. */
282    private static void redrawGraphicsInternal() {
283        if (sRedrawCallback != null)
284            sRedrawCallback.run();
285    }
286 
287    /**
288     * Obtains the image buffer.
289     * This should not be called from the UI thread. (We prefer the native graphics thread.)
290     */
291    public static Bitmap retrieveVideoFrame() {
292        if (Looper.myLooper() == Looper.getMainLooper()) {
293            Log.w("jniiface", "Canvas being redrawn on UI thread");
294        }
295 
296        if (!sConnected) {
297            return null;
298        }
299 
300        int[] frame = new int[sWidth * sHeight];
301 
302        sBuffer.order(ByteOrder.LITTLE_ENDIAN);
303        sBuffer.asIntBuffer().get(frame, 0, frame.length);
304 
305        return Bitmap.createBitmap(frame, 0, sWidth, sWidth, sHeight, Bitmap.Config.ARGB_8888);
306    }
307 
308    /** Moves the mouse cursor, possibly while clicking the specified (nonnegative) button. */
309    public static void mouseAction(int x, int y, int whichButton, boolean buttonDown) {
310        if (!sConnected) {
311            return;
312        }
313 
314        mouseActionNative(x, y, whichButton, buttonDown);
315    }
316 
317    /** Presses and releases the specified (nonnegative) key. */
318    public static void keyboardAction(int keyCode, boolean keyDown) {
319        if (!sConnected) {
320            return;
321        }
322 
323        keyboardActionNative(keyCode, keyDown);
324    }
325 
326    /** Performs the native response to the user's PIN. */
327    private static native void authenticationResponse(String pin, boolean createPair);
328 
329    /** Schedules a redraw on the native graphics thread. */
330    private static native void scheduleRedrawNative();
331 
332    /** Passes mouse information to the native handling code. */
333    private static native void mouseActionNative(int x, int y, int whichButton, boolean buttonDown);
334 
335    /** Passes key press information to the native handling code. */
336    private static native void keyboardActionNative(int keyCode, boolean keyDown);
337}

[all classes][org.chromium.chromoting.jni]
EMMA 2.0.5312 (C) Vladimir Roubtsov