EMMA Coverage Report (generated Tue Aug 20 10:07:21 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/530)0%   (0/117)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class JniInterface0%   (0/1)0%   (0/16)0%   (0/450)0%   (0/97)
<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 (): void 0%   (0/1)0%   (0/67)0%   (0/13)
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/25)0%   (0/4)
JniInterface$2 (View): void 0%   (0/1)0%   (0/6)0%   (0/1)
onClick (DialogInterface, int): void 0%   (0/1)0%   (0/19)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() {
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        pinPrompt.setPositiveButton(
199                R.string.pin_entry_connect, new DialogInterface.OnClickListener() {
200                    @Override
201                    public void onClick(DialogInterface dialog, int which) {
202                        Log.i("jniiface", "User provided a PIN code");
203                        authenticationResponse(String.valueOf(
204                                ((TextView)
205                                        pinEntry.findViewById(R.id.pin_dialog_text)).getText()),
206                                ((CheckBox)
207                                        pinEntry.findViewById(R.id.pin_dialog_check)).isChecked());
208                    }
209                });
210 
211        pinPrompt.setNegativeButton(
212                R.string.pin_entry_cancel, new DialogInterface.OnClickListener() {
213                    @Override
214                    public void onClick(DialogInterface dialog, int which) {
215                        Log.i("jniiface", "User canceled pin entry prompt");
216                        Toast.makeText(sContext,
217                                sContext.getString(R.string.msg_pin_canceled),
218                                Toast.LENGTH_LONG).show();
219                        disconnectFromHost();
220                    }
221                });
222 
223        final AlertDialog pinDialog = pinPrompt.create();
224 
225        ((TextView)pinEntry.findViewById(R.id.pin_dialog_text)).setOnEditorActionListener(
226                new TextView.OnEditorActionListener() {
227                    @Override
228                    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
229                        // The user pressed enter on the keypad (equivalent to the connect button).
230                        pinDialog.getButton(AlertDialog.BUTTON_POSITIVE).performClick();
231                        pinDialog.dismiss();
232                        return true;
233                    }
234                });
235 
236        pinDialog.setOnCancelListener(
237                new DialogInterface.OnCancelListener() {
238                    @Override
239                    public void onCancel(DialogInterface dialog) {
240                        // The user backed out of the dialog (equivalent to the cancel button).
241                        pinDialog.getButton(AlertDialog.BUTTON_NEGATIVE).performClick();
242                    }
243                });
244 
245        pinDialog.show();
246    }
247 
248    /** Saves newly-received pairing credentials to permanent storage. */
249    private static void commitPairingCredentials(String host, byte[] id, byte[] secret) {
250        synchronized (sContext) {
251            sContext.getPreferences(Activity.MODE_PRIVATE).edit().
252                    putString(host + "_id", new String(id)).
253                    putString(host + "_secret", new String(secret)).
254                    apply();
255        }
256    }
257 
258    /**
259     * Sets the redraw callback to the provided functor. Provide a value of null whenever the
260     * window is no longer visible so that we don't continue to draw onto it.
261     */
262    public static void provideRedrawCallback(Runnable redrawCallback) {
263        sRedrawCallback = redrawCallback;
264    }
265 
266    /** Forces the native graphics thread to redraw to the canvas. */
267    public static boolean redrawGraphics() {
268        synchronized(JniInterface.class) {
269            if (!sConnected || sRedrawCallback == null) return false;
270        }
271 
272        scheduleRedrawNative();
273        return true;
274    }
275 
276    /** Performs the redrawing callback. This is a no-op if the window isn't visible. */
277    private static void redrawGraphicsInternal() {
278        if (sRedrawCallback != null)
279            sRedrawCallback.run();
280    }
281 
282    /**
283     * Obtains the image buffer.
284     * This should not be called from the UI thread. (We prefer the native graphics thread.)
285     */
286    public static Bitmap retrieveVideoFrame() {
287        if (Looper.myLooper() == Looper.getMainLooper()) {
288            Log.w("jniiface", "Canvas being redrawn on UI thread");
289        }
290 
291        if (!sConnected) {
292            return null;
293        }
294 
295        int[] frame = new int[sWidth * sHeight];
296 
297        sBuffer.order(ByteOrder.LITTLE_ENDIAN);
298        sBuffer.asIntBuffer().get(frame, 0, frame.length);
299 
300        return Bitmap.createBitmap(frame, 0, sWidth, sWidth, sHeight, Bitmap.Config.ARGB_8888);
301    }
302 
303    /** Moves the mouse cursor, possibly while clicking the specified (nonnegative) button. */
304    public static void mouseAction(int x, int y, int whichButton, boolean buttonDown) {
305        if (!sConnected) {
306            return;
307        }
308 
309        mouseActionNative(x, y, whichButton, buttonDown);
310    }
311 
312    /** Presses and releases the specified (nonnegative) key. */
313    public static void keyboardAction(int keyCode, boolean keyDown) {
314        if (!sConnected) {
315            return;
316        }
317 
318        keyboardActionNative(keyCode, keyDown);
319    }
320 
321    /** Performs the native response to the user's PIN. */
322    private static native void authenticationResponse(String pin, boolean createPair);
323 
324    /** Schedules a redraw on the native graphics thread. */
325    private static native void scheduleRedrawNative();
326 
327    /** Passes mouse information to the native handling code. */
328    private static native void mouseActionNative(int x, int y, int whichButton, boolean buttonDown);
329 
330    /** Passes key press information to the native handling code. */
331    private static native void keyboardActionNative(int keyCode, boolean keyDown);
332}

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