Java tutorial
/* Copyright 2013 Oscar Crespo Salazar Copyright 2013 Gorka Jimeno Garrachon Copyright 2013 Luis Valero Martin This file is part of VNCpp. VNCpp is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version. VNCpp is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with VNCpp. If not, see <http://www.gnu.org/licenses/>. */ package es.farfuteam.vncpp.controller; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.content.res.Configuration; import android.os.Bundle; import android.support.v4.app.FragmentActivity; import android.support.v4.view.MotionEventCompat; import android.text.InputType; import android.util.Log; import android.view.GestureDetector; import android.view.GestureDetector.OnGestureListener; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.ScaleGestureDetector; import android.view.ScaleGestureDetector.OnScaleGestureListener; import android.view.Window; import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; import android.widget.TextView; import com.jeremyfeinstein.slidingmenu.lib.SlidingMenu; import java.util.Collections; import java.util.Vector; import es.farfuteam.vncpp.controller.NewConnectionActivity.QualityArray; import es.farfuteam.vncpp.model.ObserverCanvas; import es.farfuteam.vncpp.model.VncBridgeJNI; import es.farfuteam.vncpp.model.VncBridgeJNI.ConnectionError; import es.farfuteam.vncpp.model.VncBridgeJNI.MouseEvent; import es.farfuteam.vncpp.view.CanvasView; import es.farfuteam.vncpp.view.SlideListFragment; /** * @class CanvasActivity * @brief This is the activity which controls the Canvas * @authors Oscar Crespo, Gorka Jimeno, Luis Valero * @extends FragmentActivity * @implements ObserverCanvas * @details This is the activity which controls the Canvas */ public class CanvasActivity extends FragmentActivity implements ObserverCanvas { /** * @enum EnumDialogs * @authors Oscar Crespo, Gorka Jimeno, Luis Valero * @details Indicates what dialog */ public enum EnumDialogs { createServerNotFoundDialog, ///< Server not found dialog exitDialog, ///< exit dialog serverInterruptConexionDialog, ///< server interrupt connection comboEventsDialog, ///< combo events dialog functionKeysDialog, ///< function keys dialog openHelpDialog, ///< open help dialog timeExceededDialog, ///< time exceeded dialog passwordNeededDialog, ///< password needed dialog outOfMemoryDialog///< out of memory dialog } ; /** * @enum EnumSpecialKey * @autors Oscar Crespo, Gorka Jimeno, Luis Valero * @details Indicates the special keys */ public enum EnumSpecialKey { ctrl, ///< ctrl alt, ///< alt supr, ///< supr shift, ///< shift meta///< meta } ; //etiqueta debug /** * Debug tag */ private static final String DEBUG_TAG = "CanvasActivity"; /** * Velocity mode */ private static final int VELOCITY_MOD = 30; /** * Timer connection, the time out to the connection */ private static final int TIMER_CONNECTION = 30000; /** * Timer scroll, the time to wait when the drag mode is over */ private static final int TIMER_SCROLL = 500; /** * adjust key, the adjust to match the SDK key code to RFB key code */ private static final int ADJUST_KEY = 17; /** * The maximum scale factor */ private static final float MAX_ZOOM = 3; /** * The minimum scale factor */ private static final float MIN_ZOOM = 0.5f; /** * The VncBridgeJNI object */ private VncBridgeJNI vnc; /** * The CanvasView object */ private CanvasView canvas; /** * The GestureDetector object, this object captures the move gestures */ private GestureDetector gesture; /** * The ScaleGestureDetector object, this object captures the scale gestures */ private ScaleGestureDetector scaleGesture; /** * The X coordinate in the server */ private int realX = 0; /** * The Y coordinate in the server */ private int realY = 0; /** * The scale factor */ private float scaleFactor = 1; /** * The end scroll timer thread */ private Thread endScrollThread; /** * The end scroll timer Runnable, it is used with timerScroll to make the sleep when the drag mode is over */ private Runnable endScrollRun; /** * is drag, indicates if the drag mode is on or off */ private boolean drag = false; /** * is zoom, indicates if the zoom mode is on or off */ private boolean zoom = false; /** * indicates if it has to make a turn more to the loop */ private boolean oneLoopMore = false; /** * A vector with the special keys */ private Vector<EnumSpecialKey> specialKeys; /** * A vector with the keys */ private Vector<Integer> keys; /** * The SlidingMenu object */ private SlidingMenu menu; /** * is waitDialog, indicates that it has to wait the end of a dialog */ private boolean waitDialog = false; /** * The ProcessDialog dialog, is the loading canvas dialog */ private ProgressDialog progressDialog; /** * offset to adjust the shift key */ private int modKeyCount = 0; /** * The InputMethodManager object, to handle the keyboard */ private InputMethodManager inputMgr; /** * The password */ private String pass; /** * is connected, indicates to the timeout thread has not to finish the canvas */ private boolean connect = false; /** * @brief Changes the configuration when the terminal is rotate * @details Changes the configuration when the terminal is rotate */ @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); } /** * @brief The Android onCreate method * @details The Android onCreate method. Initializes the CanvasView, SlidingMenu, VncBridgeJNI. * Also calls the method to start the connection */ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //No se muestra la barra de accion superior requestWindowFeature(Window.FEATURE_NO_TITLE); this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); setContentView(R.layout.canvas); canvas = (CanvasView) findViewById(R.id.vnc_canvas); Bundle info = getIntent().getExtras(); progressDialog = new ProgressDialog(this); final String load = getString(R.string.loadingtext); final String loadImage = getString(R.string.loadingbodytext); progressDialog.setTitle(load); progressDialog.setMessage(loadImage); final String cancel = getString(R.string.cancel); progressDialog.setButton(cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { vnc.finishVnc(); finishConnection(); } }); progressDialog.show(); progressDialog.setCancelable(false); menu = new SlidingMenu(this); startSlideMenu(); runTimerConnection(); String aux_quality = info.getString("color"); QualityArray quality = QualityArray.valueOf(aux_quality); iniConnection(info.getString("ip"), info.getString("port"), info.getString("psw"), quality, info.getBoolean("wifi")); inputMgr = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); GestureListener gestureListener = new GestureListener(); gesture = new GestureDetector(gestureListener); scaleGesture = new ScaleGestureDetector(this, gestureListener); endScrollRun = new Runnable() { @Override public void run() { while (drag || oneLoopMore) { oneLoopMore = false; try { Thread.sleep(TIMER_SCROLL); } catch (InterruptedException e) { // Auto-generated catch block } } canvas.endDrag(); } }; } /** * @brief The time out thread * @details The time out thread. Waits the timerConnection and then checks the connect attribute, if it is false * then finish the Activity */ private void runTimerConnection() { final Activity activityThis = this; new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(TIMER_CONNECTION); } catch (InterruptedException e) { // Auto-generated catch block } if (!connect && progressDialog.isShowing()) { waitDialog = true; activityThis.runOnUiThread(new Runnable() { @Override public void run() { //Dialogo "Se ha excedido el tiempo de conexion" progressDialog.dismiss(); showDialog(EnumDialogs.timeExceededDialog.ordinal()); } }); new Thread(new Runnable() { @Override public void run() { while (waitDialog) ; vnc.finishVnc(); finishConnection(); } }).start(); } } }).start(); } /** * @param host The IP * @param port The port * @param pass The pasword * @param quality The image quality * @param compress The image has to be compress or not * @brief Starts the connection * @details Starts the connection. Calls the VncBridgeJNI method startConnect to start the connection. If everything ok * the connection starts and the connect attribute is set as true */ private void iniConnection(final String host, final String port, final String pass, final QualityArray quality, final Boolean compress) { vnc = new VncBridgeJNI(); vnc.addObserver(this); final Activity activityThis = this; new Thread(new Runnable() { @Override public void run() { ConnectionError error = vnc.startConnect(host, Integer.parseInt(port), pass, quality, compress, (es.farfuteam.vncpp.controller.Configuration.getInstance()).isHideMouse()); if (error != ConnectionError.ALLOK) { waitDialog = true; activityThis.runOnUiThread(new Runnable() { @Override public void run() { showDialog(EnumDialogs.createServerNotFoundDialog.ordinal()); } }); new Thread(new Runnable() { @Override public void run() { while (waitDialog) ; finishConnection(); } }).start(); return; } else { connect = true; } } }).start(); } /** * @brief Starts the SlideMenu * @details Starts the SlideMenu. Sets all the configurations */ private void startSlideMenu() { // configure the SlidingMenu //para modificar el margen de dips cambiar MARGIN_THRESHOLD en la //clase CustomViewBehind de la slideLibrary (antes a 48, bajado a 28). menu.setTouchModeAbove(SlidingMenu.TOUCHMODE_MARGIN); menu.setShadowWidthRes(R.dimen.shadow_width); menu.setShadowDrawable(R.drawable.shadow); menu.setBehindOffsetRes(R.dimen.slidingmenu_offset); menu.setFadeDegree(0.35f); menu.attachToActivity(this, SlidingMenu.SLIDING_CONTENT); menu.setMenu(R.layout.menu_frame); //lista lateral con el menu getSupportFragmentManager().beginTransaction().replace(R.id.menu_frame, new SlideListFragment()).commit(); } /** * @param keyCode The key code * @param event The event * @return True * @brief Handles the onKeyDown event * @details Handles the onKeyDown event. Only handles the back key and the menu key */ @Override public boolean onKeyDown(int keyCode, KeyEvent evt) { //super.onKeyDown(keyCode, evt); if (keyCode == KeyEvent.KEYCODE_BACK) { if (vnc != null) { //Dialog pregunta salir showDialog(EnumDialogs.exitDialog.ordinal()); } } else if (keyCode == KeyEvent.KEYCODE_MENU) { //Log.i("tag","en menu del canvas"); menu.toggle(); } return true; } /** * @param event The event * @brief Captures the keys of the keyboard * @details Capture the keys of the keyboard. If the character has to be pressed with a combination of the shift key * and other key then adds 100 to the modKeyCount attribute to applies the offset */ @Override public boolean dispatchKeyEvent(KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_DOWN || event.getAction() == KeyEvent.ACTION_UP || event.getAction() == KeyEvent.ACTION_MULTIPLE) { int keyunicode = event.getUnicodeChar(event.getMetaState()); char character = (char) keyunicode; int key = event.getKeyCode(); if (key == 59) { if (modKeyCount == 0) { modKeyCount = 100; } else { modKeyCount = 0; } } else if (key >= 7) { boolean down = event.getAction() == KeyEvent.ACTION_DOWN; vnc.sendKey(modKeyCount + key, down); } Log.e(DEBUG_TAG, String.valueOf(event.getKeyCode())); } return super.dispatchKeyEvent(event); } /** * @param keyCode The key * @param evt The event * @return true * @brief Captures the onkeyUp event * @details Captures the onKeyUp event and returns true */ @Override public boolean onKeyUp(int keyCode, KeyEvent evt) { super.onKeyUp(keyCode, evt); return true; } /** * @param event The event * @return true * @brief Captures onTouchEvent * @details Captures onTouchEvent. Sends the event to the gesture and scaleGesture objects */ @Override public boolean onTouchEvent(MotionEvent event) { super.onTouchEvent(event); scaleGesture.onTouchEvent(event); gesture.onTouchEvent(event); int action = MotionEventCompat.getActionMasked(event); switch (action) { //case (MotionEvent.ACTION_DOWN): //case (MotionEvent.ACTION_MOVE): case (MotionEvent.ACTION_UP): return onUpMouse(event); case (MotionEvent.ACTION_CANCEL): Log.d(DEBUG_TAG, "La accion ha sido CANCEL"); return true; case (MotionEvent.ACTION_OUTSIDE): Log.d(DEBUG_TAG, "La accion ha sido fuera del elemento de la pantalla"); return true; default: return true; } } /** * @param e The event * @return true * @brief Handles the onUpMouse event * @details Handles the onUpMouse event. Starts the endScrollThreads and sets the onLoopMore as true, drag as false * and zoom as false */ public boolean onUpMouse(MotionEvent e) { if (drag || zoom) { if (endScrollThread != null) { if (!endScrollThread.isAlive()) { endScrollThread = new Thread(endScrollRun); endScrollThread.start(); } } else { endScrollThread = new Thread(endScrollRun); endScrollThread.start(); } oneLoopMore = true; drag = false; zoom = false; } return true; } /** * @brief updateRedraw notification * @details updateRedraw notification. This method calls to canvas reDraw when the activity gets a notification of * redraw */ @Override public void updateRedraw() { canvas.reDraw(); if (progressDialog.isShowing()) progressDialog.dismiss(); canvas.postInvalidate(); } /** * @param data The bitmap data * @param offset The offset * @param x The x coordinate * @param y The y coordinate * @param width The image width * @param height The image height * @brief updateIniFrame notification * @details updateIniFrame notification. Calls the canvas method initCanvas */ @Override public void updateIniFrame(int[] data, int offset, int x, int y, int width, int height) { canvas.initCanvas(data, offset, width, x, y, width, height); } /** * @brief updateFinish notification * @details updateFinish notification. Ends the connection */ @Override public void updateFinish() { if (progressDialog.isShowing()) { progressDialog.dismiss(); } showDialogWait(EnumDialogs.serverInterruptConexionDialog); finishConnection(); } /** * @return The password * @brief updatePass notification * @details updatePass notification. Returns the password when the activity gets a request */ @Override public String updatePass() { showDialogWait(EnumDialogs.passwordNeededDialog); String aux_pass = pass; pass = null; return aux_pass; } /** * @brief updateOutMemory notification * @details updateOutMemory notification. If there are not enough memory, closes the connection when the activity * gets the notification */ @Override public void updateOutOfMemory() { progressDialog.dismiss(); showDialogWait(EnumDialogs.outOfMemoryDialog); if (vnc != null) vnc.finishVnc(); finishConnection(); } /** * @param dialog the dialog enum * @brief Shows a dialog * @details Shows a dialog. Shows the dialog indicated in the enum dialog parameter and waits until the dialog * is closed */ private void showDialogWait(final EnumDialogs dialog) { waitDialog = true; this.runOnUiThread(new Runnable() { @Override public void run() { showDialog(dialog.ordinal()); } }); while (waitDialog) ; } /** * @brief Makes a toggle of the keyboard * @details Makes a toggle of the keyboard */ public void showKeyboard() { inputMgr.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY); menu.toggle(); } /** * @brief Ends the connection * @details Ends the connection */ private void finishConnection() { if (progressDialog.isShowing()) { progressDialog.dismiss(); } vnc = null; finish(); } /** * @param distanceX the distance of the x coordinate * @param distanceY the distance of the y coordinate * @return true * @brief Makes the scroll * @details Makes the scroll. Checks if the move is out of the image, if it is the method recalculates the distances * and adds the distances to the current coordinates and calls the canvas method scrollTo */ private boolean doScroll(float distanceX, float distanceY) { if (!drag) { drag = true; canvas.startDrag(); } float moveX = 0; float moveY = 0; boolean allOkX = true; boolean allOkY = true; int offSetKeyboard = 0; //if(showKeyboard) offSetKeyboard = canvas.getHeight() / 2; float width = canvas.getWidth() / scaleFactor; float height = canvas.getHeight() / scaleFactor; if ((realX + width >= canvas.getRealWidth() && distanceX > 0) || (realX == 0 && distanceX < 0) || (canvas.getWidth() / scaleFactor > canvas.getRealWidth())) { moveX = 0; allOkX = false; } if ((realY + height >= canvas.getRealHeight() + offSetKeyboard && distanceY > 0) || (realY == 0 && distanceY < 0) || (canvas.getHeight() / scaleFactor > canvas.getRealHeight() + offSetKeyboard)) { moveY = 0; allOkY = false; } if (allOkX) { if (realX + width + distanceX > canvas.getRealWidth() || realX + distanceX < 0) { if (distanceX < 0) { moveX = -realX; } else { moveX = canvas.getRealWidth() - (realX + width); } allOkX = false; } } if (allOkY) { if (inputMgr.isAcceptingText()) { //offSetKeyboard = canvas.getRealHeight()/2; } if (realY + height + distanceY > canvas.getRealHeight() + offSetKeyboard || realY + distanceY < 0) { if (distanceY < 0) { moveY = -realY; } else { moveY = (canvas.getRealHeight() + offSetKeyboard) - (realY + height); } allOkY = false; } } if (allOkY) { moveY = distanceY; } if (allOkX) { moveX = distanceX; } if (moveX != 0 || moveY != 0) { realX = realX + (int) moveX; realY = realY + (int) moveY; canvas.scrollTo((int) (realX * scaleFactor), (int) (realY * scaleFactor)); } return true; } /** * @brief Centers the image * @details Centers the image. Sets the x coordinate, the y coordinate, scaleFActor to the defaults values * also calls the canvas methods scrollTo and setScale to sets the new scroll and the new scale */ private void centerImage() { realX = 0; realY = 0; canvas.scrollTo(0, 0); scaleFactor = 1; canvas.setScale(scaleFactor, 0, 0); } /** * @class GestureListener * @brief This is the Class which handles the gesture events * @authors Oscar Crespo, Gorka Jimeno, Luis Valero * @implements OnScaleGestureListener * @implements OnGestureListener * @details This is the Class which handles the gesture events. */ private class GestureListener implements OnScaleGestureListener, OnGestureListener { /** * The x coordinate */ private float x; /** * The y coordinate */ private float y; @Override public boolean onDown(MotionEvent e) { return true; } /** * @param e The event * @brief Handles the onLongPress event * @details Handles the onLongPress event. Calculates the real position of the mouse in the bitmap and * calls the VncBridgeJNI method sendMouseEvent */ @Override public void onLongPress(MotionEvent e) { if (drag) { drag = false; canvas.endDrag(); } float posX = realX + (e.getX() / scaleFactor); float posY = realY + (e.getY() / scaleFactor); if (vnc != null) vnc.sendMouseEvent((int) posX, (int) posY, MouseEvent.RightClick); } /** * @param e1 The first capture position * @param e2 The second capture position * @param velocityX The velocity of the x coordinate * @param velocityY The velocity of the y coordinate * @return true * @brief Handles the onFling event * @details Handles the onFling event. Makes scroll according to the velocity */ @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { onScroll(e1, e2, -velocityX / VELOCITY_MOD, -velocityY / VELOCITY_MOD); return true; } /** * @param e1 The first capture position * @param e2 The second capture position * @param distanceX The distance of the x coordinate between the first and the second capture * @param distanceY The distance of the y coordinate between the first and the second capture * @return true * @brief Handles the onScroll event * @details Handles the onScroll event. Calls to doScroll method */ @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { if (!zoom) { doScroll(distanceX, distanceY); } return true; } @Override public void onShowPress(MotionEvent e) { } /** * @param e The event capture * @return true * @brief Handles the onSingleTapUp event * @details Handles the onSingleTapUp event. Calculates the real position of the mouse in the bitmap and * calls the VncBridgeJNI method sendMouseEvent */ @Override public boolean onSingleTapUp(MotionEvent e) { if (drag) { drag = false; oneLoopMore = false; canvas.endDrag(); } float posX = realX + (e.getX() / scaleFactor); float posY = realY + (e.getY() / scaleFactor); if (vnc != null) vnc.sendMouseEvent((int) posX, (int) posY, MouseEvent.Click); return true; } /** * @param detector The class which stores all the event information * @return true * @brief Handles the onScale event * @details Handles the onScale event. Checks if it is zoomed or unzoomed, then calls the canvas method * scaleFactor and moves to the user current position */ @Override public boolean onScale(ScaleGestureDetector detector) { float factor = detector.getScaleFactor(); boolean isDo = false; if (factor > 1 && scaleFactor != MAX_ZOOM) { if (scaleFactor + 0.1 < MAX_ZOOM) { scaleFactor += 0.1; } else { scaleFactor = MAX_ZOOM; } isDo = true; } else if (factor < 1 && scaleFactor != MIN_ZOOM) { if (scaleFactor - 0.1 > MIN_ZOOM) { scaleFactor -= 0.1; } else { scaleFactor = MIN_ZOOM; } isDo = true; } canvas.setScale(scaleFactor, 0, 0); if (isDo) { if (factor > 1) { int moveX = (int) (x * scaleFactor); int moveY = (int) (y * scaleFactor); if (x < 0) { moveX = 0; y = 0; } if (y < 0) { moveY = 0; y = 0; } realX = (int) x; realY = (int) y; canvas.scrollTo(moveX, moveY); } else if (factor < 1) { int auxX = 0; int auxY = 0; if (x * scaleFactor > canvas.getRealWidth()) { auxX = -100; } else { auxX = -10; } if (y * scaleFactor > canvas.getRealHeight()) { auxY = -100; } else { auxY = -10; } doScroll(auxX, auxY); } } return true; } /** * @param detector The class which stores all the event information * @return true * @brief Handles the onScaleBegin event * @details Handles the onScaleBegin event. Calls the canvas method startDrag and gets the x and y coordinates */ @Override public boolean onScaleBegin(ScaleGestureDetector detector) { zoom = true; drag = true; canvas.startDrag(); x = (int) (((detector.getFocusX() / scaleFactor) + realX) - detector.getFocusX()); y = (int) (((detector.getFocusY() / scaleFactor) + realY) - detector.getFocusY()); if (x < 0) { x = 0; } if (realY < 0) { y = 0; } return true; } /** * @param detector The class which stores all the event information * @return true * @brief Handles the onScaleEnd event * @details Handles the onScaleEnd event. Calls the method doScroll to set the image */ @Override public void onScaleEnd(ScaleGestureDetector detector) { doScroll(1, 1); } } ; /** * @param id the dialog ID * @return Dialog created * @brief Override function to create dialogs * @details Create the dialog with a showDialog(id) called, * id is the number of the dialog to be created */ @Override protected Dialog onCreateDialog(int id) { Dialog dialog = null; switch (id) { case 0: dialog = createServerNotFoundDialog(); break; case 1: dialog = exitDialog(); break; case 2: dialog = serverInterruptConnectionDialog(); break; case 3: menu.toggle(); dialog = comboEventsDialog(); break; case 4: dialog = functionKeysDialog(); break; case 5: dialog = openHelpDialog(); menu.toggle(); break; case 6: dialog = timeExceededDialog(); break; case 7: dialog = passwordNeededDialog(); break; case 8: dialog = outOfMemoryDialog(); break; } return dialog; } /** * @return The new dialog * @brief Show the dialog with the password needed message * @details Show the dialog with the password needed message */ private Dialog passwordNeededDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(this); String info = getString(R.string.password_title); String body = getString(R.string.password_dialog); builder.setTitle(info); builder.setMessage(body); // Set an EditText view to get user password final EditText input = new EditText(this); input.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); builder.setView(input); builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { dialog.cancel(); pass = ""; waitDialog = false; } }); builder.setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { String str = input.getEditableText().toString(); pass = str; waitDialog = false; } }); return builder.create(); } /** * @return The new dialog * @brief Show the dialog with the server not found message * @details Show the dialog with the server not found message */ private Dialog createServerNotFoundDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(this); String info = getString(R.string.server_dialog); String body = getString(R.string.server_not_found); builder.setTitle(info); builder.setMessage(body); builder.setCancelable(false); builder.setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.cancel(); waitDialog = false; } }); return builder.create(); } /** * @return The new dialog * @brief Show the dialog with the exit question * @details Show the dialog with the exit question */ private Dialog exitDialog() { final String titleExit = getString(R.string.DialogTitleExit); final String question = getString(R.string.DialogQuestion); return new AlertDialog.Builder(this).setIcon(android.R.drawable.ic_dialog_alert).setTitle(titleExit) .setMessage(question).setNegativeButton(android.R.string.cancel, null)//sin listener .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { vnc.finishVnc(); finishConnection(); } }).show(); } /** * @return The new dialog * @brief Show the dialog with the connection interrupted message * @details Show the dialog with the connection interrupted message */ private Dialog serverInterruptConnectionDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(this); String info = getString(R.string.server_dialog); String body = getString(R.string.server_interrupt); builder.setTitle(info); builder.setMessage(body); builder.setCancelable(false); builder.setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); waitDialog = false; } }); return builder.create(); } /** * @return The new dialog * @brief Show the dialog with timeout message * @details Show the dialog with timeout message */ private Dialog timeExceededDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(this); String info = getString(R.string.time_info); String body = getString(R.string.time_exceeded); builder.setTitle(info); builder.setMessage(body); builder.setCancelable(false); builder.setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); waitDialog = false; } }); return builder.create(); } /** * @return The new dialog * @brief Show the dialog with the out of memory message * @details Show the dialog with the out of memory message */ private Dialog outOfMemoryDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(this); String info = getString(R.string.memory_info); String body = getString(R.string.memory_exceeded); builder.setTitle(info); builder.setMessage(body); builder.setCancelable(false); builder.setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); waitDialog = false; } }); return builder.create(); } /** * @param down if it is down or not the key * @brief Sends the special keys * @details Sends the special keys. Calls the VncBridgeJNI method sendKey */ private void sendSpecialKeys(boolean down) { for (EnumSpecialKey s : specialKeys) { switch (s) { case ctrl: vnc.sendKey(1, down); break; case alt: vnc.sendKey(3, down); break; case supr: vnc.sendKey(4, down); break; case shift: vnc.sendKey(2, down); break; case meta: vnc.sendKey(6, down); break; } } } /** * @param down if it is down or not the key * @brief Sends the keys * @details Sends the keys. Calls the VncBridgeJNI method sendKey */ private void sendKeys(boolean down) { if (keys != null) { for (int s : keys) { vnc.sendKey(s + ADJUST_KEY, down); } } } /** * @return The new dialog * @brief Show the dialog with the combo event * @details Show the dialog with the combo event */ private Dialog comboEventsDialog() { specialKeys = new Vector<EnumSpecialKey>(); // Where we track the selected items AlertDialog.Builder builder = new AlertDialog.Builder(this); // Set the dialog title final Activity actThis = this; builder.setCancelable(false); builder.setTitle(R.string.combo_keys_title) // Specify the list array, the items to be selected by default (null for none), // and the listener through which to receive callbacks when items are selected .setMultiChoiceItems(R.array.keys_array, null, new DialogInterface.OnMultiChoiceClickListener() { @Override public void onClick(DialogInterface dialog, int which, boolean isChecked) { EnumSpecialKey aux = EnumSpecialKey.values()[which]; ; if (isChecked) { // If the user checked the item, add it to the selected items if (aux == EnumSpecialKey.ctrl || aux == EnumSpecialKey.alt) { specialKeys.add(0, aux); } else { specialKeys.add(aux); } } else if (specialKeys.contains(which)) { // Else, if the item is already in the array, remove it specialKeys.remove(aux); } } }).setNeutralButton(R.string.function_keys_title, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { //muestra function keys showDialog(EnumDialogs.functionKeysDialog.ordinal()); } }) // Set the action buttons .setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int id) { sendSpecialKeys(true); sendKeys(true); Collections.reverse(specialKeys); if (keys != null) Collections.reverse(keys); sendKeys(false); sendSpecialKeys(false); actThis.removeDialog(EnumDialogs.comboEventsDialog.ordinal()); actThis.removeDialog(EnumDialogs.functionKeysDialog.ordinal()); specialKeys = null; keys = null; } }).setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int id) { //se vacia el vector actThis.removeDialog(EnumDialogs.comboEventsDialog.ordinal()); actThis.removeDialog(EnumDialogs.functionKeysDialog.ordinal()); specialKeys = null; keys = null; } }); return builder.create(); } /** * @return The new dialog * @brief Show the dialog with the function keys * @details Show the dialog with the function keys */ private Dialog functionKeysDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(this); if (keys == null) keys = new Vector<Integer>(); // Where we track the selected items final Activity actThis = this; // Set the dialog title builder.setCancelable(false); builder.setTitle(R.string.function_keys_title).setMultiChoiceItems(R.array.function_keys_array, null, new DialogInterface.OnMultiChoiceClickListener() { @Override public void onClick(DialogInterface dialog, int which, boolean isChecked) { if (isChecked) { // If the user checked the item, add it to the selected items keys.add(which); } else if (keys.contains(Integer.valueOf(which))) { // Else, if the item is already in the array, remove it keys.remove(Integer.valueOf(which)); } } }) // Set the action buttons .setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int id) { showDialog(EnumDialogs.comboEventsDialog.ordinal()); } }).setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int id) { showDialog(EnumDialogs.comboEventsDialog.ordinal()); actThis.removeDialog(EnumDialogs.functionKeysDialog.ordinal()); } }); return builder.create(); } /** * @return The new dialog * @brief Show the dialog with the help message * @details Show the dialog with the help message */ private Dialog openHelpDialog() { final TextView text = new TextView(this); text.setText(R.string.help_message); return new AlertDialog.Builder(this).setTitle(R.string.help_title).setView(text) .setPositiveButton(R.string.help_ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }).show(); } /** * @brief Centers the image * @details Centers the image. */ public void centerImageCanvas() { centerImage(); menu.toggle(); } }