Java tutorial
package androidVNC; /* * This 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 2 of the License, or * (at your option) any later version. * * This software 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 this software; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ // // CanvasView is the Activity for showing VNC Desktop. // import android.app.Activity; import android.app.Dialog; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.ContentValues; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnDismissListener; import android.content.Intent; import android.content.res.Configuration; import android.database.Cursor; import android.graphics.PointF; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.os.SystemClock; import android.support.v4.app.NotificationCompat; import android.util.Log; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.Window; import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.ListView; import android.widget.Toast; import com.antlersoft.android.bc.BCFactory; import com.services.MyService; import java.io.IOException; import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; import fi.aalto.openoranges.project1.mcc.MainActivity; import fi.aalto.openoranges.project1.mcc.R; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; public class VncCanvasActivity extends Activity implements View.OnGenericMotionListener { /** * @author Michael A. MacDonald */ class ZoomInputHandler extends AbstractGestureInputHandler { /** * In drag mode (entered with long press) you process mouse events * without sending them through the gesture detector */ private boolean dragMode; /** * Key handler delegate that handles DPad-based mouse motion */ private DPadMouseKeyHandler keyHandler; /** * @param */ ZoomInputHandler() { super(VncCanvasActivity.this); keyHandler = new DPadMouseKeyHandler(VncCanvasActivity.this, vncCanvas.handler); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#getHandlerDescription() */ @Override public CharSequence getHandlerDescription() { return getResources().getString(R.string.input_mode_touch_pan_zoom_mouse); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#getName() */ @Override public String getName() { return TOUCH_ZOOM_MODE; } /* * (non-Javadoc) * * @see android.androidVNC.VncCanvasActivity.ZoomInputHandler#onKeyDown(int, * android.view.KeyEvent) */ @Override public boolean onKeyDown(int keyCode, KeyEvent evt) { return keyHandler.onKeyDown(keyCode, evt); } /* * (non-Javadoc) * * @see android.androidVNC.VncCanvasActivity.ZoomInputHandler#onKeyUp(int, * android.view.KeyEvent) */ @Override public boolean onKeyUp(int keyCode, KeyEvent evt) { return keyHandler.onKeyUp(keyCode, evt); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onTrackballEvent(android.view.MotionEvent) */ @Override public boolean onTrackballEvent(MotionEvent evt) { return trackballMouse(evt); } /* * (non-Javadoc) * * @see android.view.GestureDetector.SimpleOnGestureListener#onDown(android.view.MotionEvent) */ @Override public boolean onDown(MotionEvent e) { panner.stop(); return true; } /** * Divide stated fling velocity by this amount to get initial velocity * per pan interval */ static final float FLING_FACTOR = 8; /* * (non-Javadoc) * * @see android.view.GestureDetector.SimpleOnGestureListener#onFling(android.view.MotionEvent, * android.view.MotionEvent, float, float) */ @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { showZoomer(false); panner.start(-(velocityX / FLING_FACTOR), -(velocityY / FLING_FACTOR), new Panner.VelocityUpdater() { /* * (non-Javadoc) * * @see android.androidVNC.Panner.VelocityUpdater#updateVelocity(android.graphics.Point, * long) */ @Override public boolean updateVelocity(PointF p, long interval) { double scale = Math.pow(0.8, interval / 50.0); p.x *= scale; p.y *= scale; return (Math.abs(p.x) > 0.5 || Math.abs(p.y) > 0.5); } }); return true; } /* * (non-Javadoc) * * @see android.androidVNC.AbstractGestureInputHandler#onTouchEvent(android.view.MotionEvent) */ @Override public boolean onTouchEvent(MotionEvent e) { if (dragMode) { vncCanvas.changeTouchCoordinatesToFullFrame(e); if (e.getAction() == MotionEvent.ACTION_UP) dragMode = false; return vncCanvas.processPointerEvent(e, true); } else return super.onTouchEvent(e); } @Override public boolean onGenericMotion(MotionEvent evt) { return false; } /* * (non-Javadoc) * * @see android.view.GestureDetector.SimpleOnGestureListener#onLongPress(android.view.MotionEvent) */ @Override public void onLongPress(MotionEvent e) { showZoomer(true); BCFactory.getInstance().getBCHaptic().performLongPressHaptic(vncCanvas); dragMode = true; vncCanvas.processPointerEvent(vncCanvas.changeTouchCoordinatesToFullFrame(e), true); } /* * (non-Javadoc) * * @see android.view.GestureDetector.SimpleOnGestureListener#onScroll(android.view.MotionEvent, * android.view.MotionEvent, float, float) */ @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { if (inScaling) return false; showZoomer(false); return vncCanvas.pan((int) distanceX, (int) distanceY); } /* * (non-Javadoc) * * @see android.view.GestureDetector.SimpleOnGestureListener#onSingleTapConfirmed(android.view.MotionEvent) */ @Override public boolean onSingleTapConfirmed(MotionEvent e) { vncCanvas.changeTouchCoordinatesToFullFrame(e); vncCanvas.processPointerEvent(e, true); e.setAction(MotionEvent.ACTION_UP); return vncCanvas.processPointerEvent(e, false); } /* * (non-Javadoc) * * @see android.view.GestureDetector.SimpleOnGestureListener#onDoubleTap(android.view.MotionEvent) */ @Override public boolean onDoubleTap(MotionEvent e) { vncCanvas.changeTouchCoordinatesToFullFrame(e); vncCanvas.processPointerEvent(e, true, true); e.setAction(MotionEvent.ACTION_UP); return vncCanvas.processPointerEvent(e, false, true); } } public class TouchpadInputHandler extends AbstractGestureInputHandler { /** * In drag mode (entered with long press) you process mouse events * without sending them through the gesture detector */ private boolean dragMode; float dragX, dragY; /** * Key handler delegate that handles DPad-based mouse motion */ private DPadMouseKeyHandler keyHandler; TouchpadInputHandler() { super(VncCanvasActivity.this); keyHandler = new DPadMouseKeyHandler(VncCanvasActivity.this, vncCanvas.handler); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#getHandlerDescription() */ @Override public CharSequence getHandlerDescription() { return getResources().getString(R.string.input_mode_touchpad); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#getName() */ @Override public String getName() { return TOUCHPAD_MODE; } /* * (non-Javadoc) * * @see android.androidVNC.VncCanvasActivity.ZoomInputHandler#onKeyDown(int, * android.view.KeyEvent) */ @Override public boolean onKeyDown(int keyCode, KeyEvent evt) { return keyHandler.onKeyDown(keyCode, evt); } /* * (non-Javadoc) * * @see android.androidVNC.VncCanvasActivity.ZoomInputHandler#onKeyUp(int, * android.view.KeyEvent) */ @Override public boolean onKeyUp(int keyCode, KeyEvent evt) { return keyHandler.onKeyUp(keyCode, evt); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onTrackballEvent(android.view.MotionEvent) */ @Override public boolean onTrackballEvent(MotionEvent evt) { return trackballMouse(evt); } /** * scale down delta when it is small. This will allow finer control * when user is making a small movement on touch screen. * Scale up delta when delta is big. This allows fast mouse movement when * user is flinging. * * @param * @return */ private float fineCtrlScale(float delta) { float sign = (delta > 0) ? 1 : -1; delta = Math.abs(delta); if (delta >= 1 && delta <= 3) { delta = 1; } else if (delta <= 10) { delta *= 0.34; } else if (delta <= 30) { delta *= delta / 30; } else if (delta <= 90) { delta *= (delta / 30); } else { delta *= 3.0; } return sign * delta; } /* * (non-Javadoc) * * @see android.view.GestureDetector.SimpleOnGestureListener#onLongPress(android.view.MotionEvent) */ @Override public void onLongPress(MotionEvent e) { showZoomer(true); BCFactory.getInstance().getBCHaptic().performLongPressHaptic(vncCanvas); dragMode = true; dragX = e.getX(); dragY = e.getY(); // send a mouse down event to the remote without moving the mouse. remoteMouseStayPut(e); vncCanvas.processPointerEvent(e, true); } /* * (non-Javadoc) * * @see android.view.GestureDetector.SimpleOnGestureListener#onScroll(android.view.MotionEvent, * android.view.MotionEvent, float, float) */ @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { if (BCFactory.getInstance().getBCMotionEvent().getPointerCount(e2) > 1) { if (inScaling) return false; showZoomer(false); return vncCanvas.pan((int) distanceX, (int) distanceY); } else { // compute the relative movement offset on the remote screen. float deltaX = -distanceX * vncCanvas.getScale(); float deltaY = -distanceY * vncCanvas.getScale(); deltaX = fineCtrlScale(deltaX); deltaY = fineCtrlScale(deltaY); // compute the absolution new mouse pos on the remote site. float newRemoteX = vncCanvas.mouseX + deltaX; float newRemoteY = vncCanvas.mouseY + deltaY; if (dragMode) { if (e2.getAction() == MotionEvent.ACTION_UP) dragMode = false; dragX = e2.getX(); dragY = e2.getY(); e2.setLocation(newRemoteX, newRemoteY); return vncCanvas.processPointerEvent(e2, true); } else { e2.setLocation(newRemoteX, newRemoteY); vncCanvas.processPointerEvent(e2, false); } } return true; } /* * (non-Javadoc) * * @see android.androidVNC.AbstractGestureInputHandler#onTouchEvent(android.view.MotionEvent) */ @Override public boolean onTouchEvent(MotionEvent e) { if (dragMode) { // compute the relative movement offset on the remote screen. float deltaX = (e.getX() - dragX) * vncCanvas.getScale(); float deltaY = (e.getY() - dragY) * vncCanvas.getScale(); dragX = e.getX(); dragY = e.getY(); deltaX = fineCtrlScale(deltaX); deltaY = fineCtrlScale(deltaY); // compute the absolution new mouse pos on the remote site. float newRemoteX = vncCanvas.mouseX + deltaX; float newRemoteY = vncCanvas.mouseY + deltaY; if (e.getAction() == MotionEvent.ACTION_UP) dragMode = false; e.setLocation(newRemoteX, newRemoteY); return vncCanvas.processPointerEvent(e, true); } else return super.onTouchEvent(e); } @Override public boolean onGenericMotion(MotionEvent evt) { return false; } /** * Modify the event so that it does not move the mouse on the * remote server. * * @param e */ private void remoteMouseStayPut(MotionEvent e) { e.setLocation(vncCanvas.mouseX, vncCanvas.mouseY); } /* * (non-Javadoc) * confirmed single tap: do a single mouse click on remote without moving the mouse. * @see android.view.GestureDetector.SimpleOnGestureListener#onSingleTapConfirmed(android.view.MotionEvent) */ @Override public boolean onSingleTapConfirmed(MotionEvent e) { boolean multiTouch = (BCFactory.getInstance().getBCMotionEvent().getPointerCount(e) > 1); remoteMouseStayPut(e); vncCanvas.processPointerEvent(e, true, multiTouch || vncCanvas.cameraButtonDown); e.setAction(MotionEvent.ACTION_UP); return vncCanvas.processPointerEvent(e, false, multiTouch || vncCanvas.cameraButtonDown); } /* * (non-Javadoc) * double tap: do two left mouse right mouse clicks on remote without moving the mouse. * @see android.view.GestureDetector.SimpleOnGestureListener#onDoubleTap(android.view.MotionEvent) */ @Override public boolean onDoubleTap(MotionEvent e) { remoteMouseStayPut(e); vncCanvas.processPointerEvent(e, true, true); e.setAction(MotionEvent.ACTION_UP); return vncCanvas.processPointerEvent(e, false, true); } /* * (non-Javadoc) * * @see android.view.GestureDetector.SimpleOnGestureListener#onDown(android.view.MotionEvent) */ @Override public boolean onDown(MotionEvent e) { panner.stop(); return true; } } private final static String TAG = "VncCanvasActivity"; AbstractInputHandler inputHandler; VncCanvas vncCanvas; VncDatabase database; private MenuItem[] inputModeMenuItems; private AbstractInputHandler inputModeHandlers[]; private ConnectionBean connection; private boolean trackballButtonDown; private static final int inputModeIds[] = { R.id.itemInputFitToScreen, R.id.itemInputTouchpad, R.id.itemInputMouse, R.id.itemInputHardwareMouse, R.id.itemInputPan, R.id.itemInputTouchPanTrackballMouse, R.id.itemInputDPadPanTouchMouse, R.id.itemInputTouchPanZoomMouse }; ZoomControls zoomer; Panner panner; Button backButton; private String mToken; private String mId; private String mName; private final int mNotifyId = 1; OkHttpClient client = new OkHttpClient(); private cancelApplication mCancelApplication = null; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); database = new VncDatabase(this); connection = new ConnectionBean(); Intent i = getIntent(); Uri data = i.getData(); if ((data != null) && (data.getScheme().equals("vnc"))) { String host = data.getHost(); // This should not happen according to Uri contract, but bug introduced in Froyo (2.2) // has made this parsing of host necessary int index = host.indexOf(':'); int port; if (index != -1) { try { port = Integer.parseInt(host.substring(index + 1)); } catch (NumberFormatException nfe) { port = 0; } host = host.substring(0, index); } else { port = data.getPort(); } if (host.equals(VncConstants.CONNECTION)) { if (connection.Gen_read(database.getReadableDatabase(), port)) { MostRecentBean bean = androidVNC.getMostRecent(database.getReadableDatabase()); if (bean != null) { bean.setConnectionId(connection.get_Id()); bean.Gen_update(database.getWritableDatabase()); } } } else { connection.setAddress(host); connection.setNickname(connection.getAddress()); connection.setPort(port); List<String> path = data.getPathSegments(); if (path.size() >= 1) { connection.setColorModel(path.get(0)); } if (path.size() >= 2) { connection.setPassword(path.get(1)); } connection.save(database.getWritableDatabase()); } } else { Bundle extras = i.getExtras(); if (extras != null) { connection.Gen_populate((ContentValues) extras.getParcelable(VncConstants.CONNECTION)); } if (connection.getPort() == 0) connection.setPort(5900); // Parse a HOST:PORT entry String host = connection.getAddress(); if (host.indexOf(':') > -1) { String p = host.substring(host.indexOf(':') + 1); try { connection.setPort(Integer.parseInt(p)); } catch (Exception e) { } connection.setAddress(host.substring(0, host.indexOf(':'))); } } try { setContentView(fi.aalto.openoranges.project1.mcc.R.layout.canvas); vncCanvas = (VncCanvas) findViewById(fi.aalto.openoranges.project1.mcc.R.id.vnc_canvas); zoomer = (ZoomControls) findViewById(R.id.zoomer); } catch (Exception e) { e.printStackTrace(); } vncCanvas.initializeVncCanvas(connection, new Runnable() { public void run() { setModes(); } }); vncCanvas.setOnGenericMotionListener(this); zoomer.hide(); zoomer.setOnZoomInClickListener(new View.OnClickListener() { /* * (non-Javadoc) * * @see android.view.View.OnClickListener#onClick(android.view.View) */ @Override public void onClick(View v) { showZoomer(true); vncCanvas.scaling.zoomIn(VncCanvasActivity.this); } }); zoomer.setOnZoomOutClickListener(new View.OnClickListener() { /* * (non-Javadoc) * * @see android.view.View.OnClickListener#onClick(android.view.View) */ @Override public void onClick(View v) { showZoomer(true); vncCanvas.scaling.zoomOut(VncCanvasActivity.this); } }); zoomer.setOnZoomKeyboardClickListener(new View.OnClickListener() { /* * (non-Javadoc) * * @see android.view.View.OnClickListener#onClick(android.view.View) */ @Override public void onClick(View v) { InputMethodManager inputMgr = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); inputMgr.toggleSoftInput(0, 0); } }); panner = new Panner(this, vncCanvas.handler); inputHandler = getInputHandlerById(fi.aalto.openoranges.project1.mcc.R.id.itemInputFitToScreen); mToken = getIntent().getStringExtra("token"); mId = getIntent().getStringExtra("id"); mName = getIntent().getStringExtra("name"); //listener for the back-button registerClickCallback(); //Notification in status bar NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(VncCanvasActivity.this) .setSmallIcon(R.drawable.icon_white).setContentTitle(mName + " running") .setContentText("Click to open the application screen"); // Creates an explicit intent for an Activity in your app Intent resultIntent = new Intent(VncCanvasActivity.this, VncCanvasActivity.class); resultIntent.setAction(Long.toString(System.currentTimeMillis())); mBuilder.setContentIntent(PendingIntent.getActivity(VncCanvasActivity.this, 0, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT)); NotificationManager mNotificationManager = (NotificationManager) getSystemService( Context.NOTIFICATION_SERVICE); // mNotifyID allows you to update the notification later on. mNotificationManager.notify(mNotifyId, mBuilder.build()); startService(); } //calls mCancelAPPLICATIOn to exit and shutting down the VM private void registerClickCallback() { backButton = (Button) findViewById(R.id.back); backButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { mCancelApplication = new VncCanvasActivity.cancelApplication(); mCancelApplication.execute((Void) null); } }); } public Response DELETE(String url) throws IOException { Request request = new Request.Builder().url(url).delete().addHeader("Authorization", mToken).build(); return client.newCall(request).execute(); } /** * Represents an asynchronous task used to exit and tell server to shut vm on cloud */ public class cancelApplication extends AsyncTask<Void, Void, Boolean> { @Override protected Boolean doInBackground(Void... params) { try { String server_url = getString(R.string.server); Response response = VncCanvasActivity.this.DELETE(server_url + "application/" + mId); int code = response.code(); if (code == 202) { return true; } else if (code == 401) { return true; } else if (code == 404) { return true; } else { return false; } } catch (Exception i) { i.printStackTrace(); return false; } } protected void onPostExecute(Boolean success) { mCancelApplication = null; if (success) { Toast.makeText(VncCanvasActivity.this, "VM has been terminated!", Toast.LENGTH_SHORT).show(); NotificationManager mNotificationManager = (NotificationManager) getSystemService( Context.NOTIFICATION_SERVICE); mNotificationManager.cancel(mNotifyId); stopService(); Intent intent = new Intent(VncCanvasActivity.this, MainActivity.class); intent.putExtra("token", mToken); startActivity(intent); vncCanvas.closeConnection(); finish(); } else { vncCanvas.closeConnection(); finish(); } } @Override protected void onCancelled() { mCancelApplication = null; } } /** * Set modes on start to match what is specified in the ConnectionBean; * color mode (already done) scaling, input mode */ void setModes() { AbstractInputHandler handler = getInputHandlerByName(connection.getInputMode()); AbstractScaling.getByScaleType(connection.getScaleMode()).setScaleTypeForActivity(this); this.inputHandler = handler; showPanningState(); vncCanvas.scaling.zoomIn(VncCanvasActivity.this); vncCanvas.scaling.zoomIn(VncCanvasActivity.this); vncCanvas.scaling.zoomIn(VncCanvasActivity.this); } ConnectionBean getConnection() { return connection; } /* * (non-Javadoc) * * @see android.app.Activity#onCreateDialog(int) */ @Override protected Dialog onCreateDialog(int id) { switch (id) { case fi.aalto.openoranges.project1.mcc.R.layout.entertext: return new EnterTextDialog(this); } // Default to meta key dialog return new MetaKeyDialog(this); } /* * (non-Javadoc) * * @see android.app.Activity#onPrepareDialog(int, android.app.Dialog) */ @Override protected void onPrepareDialog(int id, Dialog dialog) { super.onPrepareDialog(id, dialog); if (dialog instanceof ConnectionSettable) ((ConnectionSettable) dialog).setConnection(connection); } @Override public void onConfigurationChanged(Configuration newConfig) { // ignore orientation/keyboard change super.onConfigurationChanged(newConfig); } @Override protected void onStop() { vncCanvas.disableRepaints(); super.onStop(); } @Override protected void onRestart() { vncCanvas.enableRepaints(); super.onRestart(); } /** * {@inheritDoc} */ @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(fi.aalto.openoranges.project1.mcc.R.menu.vnccanvasactivitymenu, menu); if (vncCanvas.scaling != null) menu.findItem(vncCanvas.scaling.getId()).setChecked(true); Menu inputMenu = menu.findItem(fi.aalto.openoranges.project1.mcc.R.id.itemInputMode).getSubMenu(); inputModeMenuItems = new MenuItem[inputModeIds.length]; for (int i = 0; i < inputModeIds.length; i++) { inputModeMenuItems[i] = inputMenu.findItem(inputModeIds[i]); } updateInputMenu(); menu.findItem(fi.aalto.openoranges.project1.mcc.R.id.itemFollowMouse) .setChecked(connection.getFollowMouse()); menu.findItem(fi.aalto.openoranges.project1.mcc.R.id.itemFollowPan).setChecked(connection.getFollowPan()); return true; } /** * Change the input mode sub-menu to reflect change in scaling */ void updateInputMenu() { if (inputModeMenuItems == null || vncCanvas.scaling == null) { return; } for (MenuItem item : inputModeMenuItems) { item.setEnabled(vncCanvas.scaling.isValidInputMode(item.getItemId())); if (getInputHandlerById(item.getItemId()) == inputHandler) item.setChecked(true); } } /** * If id represents an input handler, return that; otherwise return null * * @param id * @return */ AbstractInputHandler getInputHandlerById(int id) { if (inputModeHandlers == null) { inputModeHandlers = new AbstractInputHandler[inputModeIds.length]; } for (int i = 0; i < inputModeIds.length; ++i) { if (inputModeIds[i] == id) { if (inputModeHandlers[i] == null) { switch (id) { case fi.aalto.openoranges.project1.mcc.R.id.itemInputFitToScreen: inputModeHandlers[i] = new FitToScreenMode(); break; case fi.aalto.openoranges.project1.mcc.R.id.itemInputPan: inputModeHandlers[i] = new PanMode(); break; case fi.aalto.openoranges.project1.mcc.R.id.itemInputMouse: inputModeHandlers[i] = new MouseMode(); break; case fi.aalto.openoranges.project1.mcc.R.id.itemInputHardwareMouse: inputModeHandlers[i] = new HardwareMouseMode(); break; case fi.aalto.openoranges.project1.mcc.R.id.itemInputTouchPanTrackballMouse: inputModeHandlers[i] = new TouchPanTrackballMouse(); break; case fi.aalto.openoranges.project1.mcc.R.id.itemInputDPadPanTouchMouse: inputModeHandlers[i] = new DPadPanTouchMouseMode(); break; case fi.aalto.openoranges.project1.mcc.R.id.itemInputTouchPanZoomMouse: inputModeHandlers[i] = new ZoomInputHandler(); break; case fi.aalto.openoranges.project1.mcc.R.id.itemInputTouchpad: inputModeHandlers[i] = new TouchpadInputHandler(); break; } } return inputModeHandlers[i]; } } return null; } AbstractInputHandler getInputHandlerByName(String name) { AbstractInputHandler result = null; for (int id : inputModeIds) { AbstractInputHandler handler = getInputHandlerById(id); if (handler.getName().equals(name)) { result = handler; break; } } if (result == null) { result = getInputHandlerById(fi.aalto.openoranges.project1.mcc.R.id.itemInputTouchPanZoomMouse); } return result; } int getModeIdFromHandler(AbstractInputHandler handler) { for (int id : inputModeIds) { if (handler == getInputHandlerById(id)) return id; } return fi.aalto.openoranges.project1.mcc.R.id.itemInputTouchPanZoomMouse; } @Override public boolean onOptionsItemSelected(MenuItem item) { vncCanvas.afterMenu = true; switch (item.getItemId()) { case fi.aalto.openoranges.project1.mcc.R.id.itemInfo: vncCanvas.showConnectionInfo(); return true; case fi.aalto.openoranges.project1.mcc.R.id.itemSpecialKeys: showDialog(fi.aalto.openoranges.project1.mcc.R.layout.metakey); return true; case fi.aalto.openoranges.project1.mcc.R.id.itemColorMode: selectColorModel(); return true; // Following sets one of the scaling options case fi.aalto.openoranges.project1.mcc.R.id.itemZoomable: case fi.aalto.openoranges.project1.mcc.R.id.itemOneToOne: case fi.aalto.openoranges.project1.mcc.R.id.itemFitToScreen: AbstractScaling.getById(item.getItemId()).setScaleTypeForActivity(this); item.setChecked(true); showPanningState(); return true; case fi.aalto.openoranges.project1.mcc.R.id.itemCenterMouse: vncCanvas.warpMouse(vncCanvas.absoluteXPosition + vncCanvas.getVisibleWidth() / 2, vncCanvas.absoluteYPosition + vncCanvas.getVisibleHeight() / 2); return true; case fi.aalto.openoranges.project1.mcc.R.id.itemDisconnect: vncCanvas.closeConnection(); finish(); return true; case fi.aalto.openoranges.project1.mcc.R.id.itemEnterText: showDialog(fi.aalto.openoranges.project1.mcc.R.layout.entertext); return true; case fi.aalto.openoranges.project1.mcc.R.id.itemCtrlAltDel: vncCanvas.sendMetaKey(MetaKeyBean.keyCtrlAltDel); return true; case fi.aalto.openoranges.project1.mcc.R.id.itemFollowMouse: boolean newFollow = !connection.getFollowMouse(); item.setChecked(newFollow); connection.setFollowMouse(newFollow); if (newFollow) { vncCanvas.panToMouse(); } connection.save(database.getWritableDatabase()); return true; case fi.aalto.openoranges.project1.mcc.R.id.itemFollowPan: boolean newFollowPan = !connection.getFollowPan(); item.setChecked(newFollowPan); connection.setFollowPan(newFollowPan); connection.save(database.getWritableDatabase()); return true; case fi.aalto.openoranges.project1.mcc.R.id.itemArrowLeft: vncCanvas.sendMetaKey(MetaKeyBean.keyArrowLeft); return true; case fi.aalto.openoranges.project1.mcc.R.id.itemArrowUp: vncCanvas.sendMetaKey(MetaKeyBean.keyArrowUp); return true; case fi.aalto.openoranges.project1.mcc.R.id.itemArrowRight: vncCanvas.sendMetaKey(MetaKeyBean.keyArrowRight); return true; case fi.aalto.openoranges.project1.mcc.R.id.itemArrowDown: vncCanvas.sendMetaKey(MetaKeyBean.keyArrowDown); return true; case fi.aalto.openoranges.project1.mcc.R.id.itemSendKeyAgain: sendSpecialKeyAgain(); return true; case fi.aalto.openoranges.project1.mcc.R.id.itemOpenDoc: Utils.showDocumentation(this); return true; default: AbstractInputHandler input = getInputHandlerById(item.getItemId()); if (input != null) { inputHandler = input; connection.setInputMode(input.getName()); if (input.getName().equals(TOUCHPAD_MODE)) connection.setFollowMouse(true); item.setChecked(true); showPanningState(); connection.save(database.getWritableDatabase()); return true; } } return super.onOptionsItemSelected(item); } private MetaKeyBean lastSentKey; private void sendSpecialKeyAgain() { if (lastSentKey == null || lastSentKey.get_Id() != connection.getLastMetaKeyId()) { ArrayList<MetaKeyBean> keys = new ArrayList<MetaKeyBean>(); Cursor c = database.getReadableDatabase() .rawQuery( MessageFormat.format("SELECT * FROM {0} WHERE {1} = {2}", MetaKeyBean.GEN_TABLE_NAME, MetaKeyBean.GEN_FIELD__ID, connection.getLastMetaKeyId()), MetaKeyDialog.EMPTY_ARGS); MetaKeyBean.Gen_populateFromCursor(c, keys, MetaKeyBean.NEW); c.close(); if (keys.size() > 0) { lastSentKey = keys.get(0); } else { lastSentKey = null; } } if (lastSentKey != null) vncCanvas.sendMetaKey(lastSentKey); } @Override protected void onDestroy() { super.onDestroy(); if (isFinishing()) { vncCanvas.closeConnection(); vncCanvas.onDestroy(); database.close(); } } @Override public boolean onKeyDown(int keyCode, KeyEvent evt) { if (keyCode == KeyEvent.KEYCODE_MENU) return super.onKeyDown(keyCode, evt); return inputHandler.onKeyDown(keyCode, evt); } @Override public boolean onKeyUp(int keyCode, KeyEvent evt) { if (keyCode == KeyEvent.KEYCODE_MENU) return super.onKeyUp(keyCode, evt); return inputHandler.onKeyUp(keyCode, evt); } public void showPanningState() { //Toast.makeText(this, inputHandler.getHandlerDescription(), Toast.LENGTH_SHORT).show(); } /* * (non-Javadoc) * * @see android.app.Activity#onTrackballEvent(android.view.MotionEvent) */ @Override public boolean onTrackballEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: trackballButtonDown = true; break; case MotionEvent.ACTION_UP: trackballButtonDown = false; break; } return inputHandler.onTrackballEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { return inputHandler.onTouchEvent(event); } @Override public boolean onGenericMotion(View view, MotionEvent motionEvent) { return inputHandler.onGenericMotion(motionEvent); } private void selectColorModel() { // Stop repainting the desktop // because the display is composited! vncCanvas.disableRepaints(); String[] choices = new String[COLORMODEL.values().length]; int currentSelection = -1; for (int i = 0; i < choices.length; i++) { COLORMODEL cm = COLORMODEL.values()[i]; choices[i] = cm.toString(); if (vncCanvas.isColorModel(cm)) currentSelection = i; } final Dialog dialog = new Dialog(this); dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); ListView list = new ListView(this); list.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_checked, choices)); list.setChoiceMode(ListView.CHOICE_MODE_SINGLE); list.setItemChecked(currentSelection, true); list.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { dialog.dismiss(); COLORMODEL cm = COLORMODEL.values()[arg2]; vncCanvas.setColorModel(cm); connection.setColorModel(cm.nameString()); connection.save(database.getWritableDatabase()); //Toast.makeText(VncCanvasActivity.this,"Updating Color Model to " + cm.toString(), Toast.LENGTH_SHORT).show(); } }); dialog.setOnDismissListener(new OnDismissListener() { @Override public void onDismiss(DialogInterface arg0) { Log.i(TAG, "Color Model Selector dismissed"); // Restore desktop repaints vncCanvas.enableRepaints(); } }); dialog.setContentView(list); dialog.show(); } float panTouchX, panTouchY; /** * Pan based on touch motions * * @param event */ private boolean pan(MotionEvent event) { float curX = event.getX(); float curY = event.getY(); int dX = (int) (panTouchX - curX); int dY = (int) (panTouchY - curY); return vncCanvas.pan(dX, dY); } boolean defaultKeyDownHandler(int keyCode, KeyEvent evt) { if (vncCanvas.processLocalKeyEvent(keyCode, evt)) return true; return super.onKeyDown(keyCode, evt); } boolean defaultKeyUpHandler(int keyCode, KeyEvent evt) { if (vncCanvas.processLocalKeyEvent(keyCode, evt)) return true; return super.onKeyUp(keyCode, evt); } boolean touchPan(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: panTouchX = event.getX(); panTouchY = event.getY(); break; case MotionEvent.ACTION_MOVE: pan(event); panTouchX = event.getX(); panTouchY = event.getY(); break; case MotionEvent.ACTION_UP: pan(event); break; } return true; } private static int convertTrackballDelta(double delta) { return (int) Math.pow(Math.abs(delta) * 6.01, 2.5) * (delta < 0.0 ? -1 : 1); } boolean trackballMouse(MotionEvent evt) { int dx = convertTrackballDelta(evt.getX()); int dy = convertTrackballDelta(evt.getY()); evt.offsetLocation(vncCanvas.mouseX + dx - evt.getX(), vncCanvas.mouseY + dy - evt.getY()); if (vncCanvas.processPointerEvent(evt, trackballButtonDown)) { return true; } return VncCanvasActivity.super.onTouchEvent(evt); } long hideZoomAfterMs; static final long ZOOM_HIDE_DELAY_MS = 2500; HideZoomRunnable hideZoomInstance = new HideZoomRunnable(); private void showZoomer(boolean force) { if (force || zoomer.getVisibility() != View.VISIBLE) { zoomer.show(); hideZoomAfterMs = SystemClock.uptimeMillis() + ZOOM_HIDE_DELAY_MS; vncCanvas.handler.postAtTime(hideZoomInstance, hideZoomAfterMs + 10); } } private class HideZoomRunnable implements Runnable { public void run() { if (SystemClock.uptimeMillis() >= hideZoomAfterMs) { zoomer.hide(); } } } /** * Touches and dpad (trackball) pan the screen * * @author Michael A. MacDonald */ class PanMode implements AbstractInputHandler { /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onKeyDown(int, * android.view.KeyEvent) */ @Override public boolean onKeyDown(int keyCode, KeyEvent evt) { // DPAD KeyDown events are move MotionEvents in Panning Mode final int dPos = 100; boolean result = false; switch (keyCode) { case KeyEvent.KEYCODE_DPAD_CENTER: result = true; break; case KeyEvent.KEYCODE_DPAD_LEFT: onTouchEvent(MotionEvent.obtain(1, System.currentTimeMillis(), MotionEvent.ACTION_MOVE, panTouchX + dPos, panTouchY, 0)); result = true; break; case KeyEvent.KEYCODE_DPAD_RIGHT: onTouchEvent(MotionEvent.obtain(1, System.currentTimeMillis(), MotionEvent.ACTION_MOVE, panTouchX - dPos, panTouchY, 0)); result = true; break; case KeyEvent.KEYCODE_DPAD_UP: onTouchEvent(MotionEvent.obtain(1, System.currentTimeMillis(), MotionEvent.ACTION_MOVE, panTouchX, panTouchY + dPos, 0)); result = true; break; case KeyEvent.KEYCODE_DPAD_DOWN: onTouchEvent(MotionEvent.obtain(1, System.currentTimeMillis(), MotionEvent.ACTION_MOVE, panTouchX, panTouchY - dPos, 0)); result = true; break; default: result = defaultKeyDownHandler(keyCode, evt); break; } return result; } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onKeyUp(int, * android.view.KeyEvent) */ @Override public boolean onKeyUp(int keyCode, KeyEvent evt) { // Ignore KeyUp events for DPAD keys in Panning Mode; trackball // button switches to mouse mode switch (keyCode) { case KeyEvent.KEYCODE_DPAD_CENTER: inputHandler = getInputHandlerById(fi.aalto.openoranges.project1.mcc.R.id.itemInputMouse); connection.setInputMode(inputHandler.getName()); connection.save(database.getWritableDatabase()); updateInputMenu(); showPanningState(); return true; case KeyEvent.KEYCODE_DPAD_LEFT: return true; case KeyEvent.KEYCODE_DPAD_RIGHT: return true; case KeyEvent.KEYCODE_DPAD_UP: return true; case KeyEvent.KEYCODE_DPAD_DOWN: return true; } return defaultKeyUpHandler(keyCode, evt); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onTouchEvent(android.view.MotionEvent) */ @Override public boolean onTouchEvent(MotionEvent event) { return touchPan(event); } @Override public boolean onGenericMotion(MotionEvent evt) { return false; } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onTrackballEvent(android.view.MotionEvent) */ @Override public boolean onTrackballEvent(MotionEvent evt) { return false; } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#handlerDescription() */ @Override public CharSequence getHandlerDescription() { return getResources().getText(R.string.input_mode_panning); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#getName() */ @Override public String getName() { return "PAN_MODE"; } } /** * The touchscreen pans the screen; the trackball moves and clicks the * mouse. * * @author Michael A. MacDonald */ public class TouchPanTrackballMouse implements AbstractInputHandler { private DPadMouseKeyHandler keyHandler = new DPadMouseKeyHandler(VncCanvasActivity.this, vncCanvas.handler); /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onKeyDown(int, * android.view.KeyEvent) */ @Override public boolean onKeyDown(int keyCode, KeyEvent evt) { return keyHandler.onKeyDown(keyCode, evt); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onKeyUp(int, * android.view.KeyEvent) */ @Override public boolean onKeyUp(int keyCode, KeyEvent evt) { return keyHandler.onKeyUp(keyCode, evt); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onTouchEvent(android.view.MotionEvent) */ @Override public boolean onTouchEvent(MotionEvent evt) { return touchPan(evt); } @Override public boolean onGenericMotion(MotionEvent evt) { return false; } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onTrackballEvent(android.view.MotionEvent) */ @Override public boolean onTrackballEvent(MotionEvent evt) { return trackballMouse(evt); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#handlerDescription() */ @Override public CharSequence getHandlerDescription() { return getResources().getText(R.string.input_mode_touchpad_pan_trackball_mouse); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#getName() */ @Override public String getName() { return "TOUCH_PAN_TRACKBALL_MOUSE"; } } static final String FIT_SCREEN_NAME = "FIT_SCREEN"; /** * Internal name for default input mode with Zoom scaling */ static final String TOUCH_ZOOM_MODE = "TOUCH_ZOOM_MODE"; static final String TOUCHPAD_MODE = "TOUCHPAD_MODE"; /** * In fit-to-screen mode, no panning. Trackball and touchscreen work as * mouse. * * @author Michael A. MacDonald */ public class FitToScreenMode implements AbstractInputHandler { private DPadMouseKeyHandler keyHandler = new DPadMouseKeyHandler(VncCanvasActivity.this, vncCanvas.handler); /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onKeyDown(int, * android.view.KeyEvent) */ @Override public boolean onKeyDown(int keyCode, KeyEvent evt) { return keyHandler.onKeyDown(keyCode, evt); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onKeyUp(int, * android.view.KeyEvent) */ @Override public boolean onKeyUp(int keyCode, KeyEvent evt) { return keyHandler.onKeyUp(keyCode, evt); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onTouchEvent(android.view.MotionEvent) */ @Override public boolean onTouchEvent(MotionEvent evt) { return false; } @Override public boolean onGenericMotion(MotionEvent evt) { return false; } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onTrackballEvent(android.view.MotionEvent) */ @Override public boolean onTrackballEvent(MotionEvent evt) { return trackballMouse(evt); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#handlerDescription() */ @Override public CharSequence getHandlerDescription() { return getResources().getText(R.string.input_mode_fit_to_screen); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#getName() */ @Override public String getName() { return FIT_SCREEN_NAME; } } /** * Touch screen controls, clicks the mouse. * * @author Michael A. MacDonald */ class MouseMode implements AbstractInputHandler { /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onKeyDown(int, * android.view.KeyEvent) */ @Override public boolean onKeyDown(int keyCode, KeyEvent evt) { if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) return true; return defaultKeyDownHandler(keyCode, evt); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onKeyUp(int, * android.view.KeyEvent) */ @Override public boolean onKeyUp(int keyCode, KeyEvent evt) { if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) { inputHandler = getInputHandlerById(fi.aalto.openoranges.project1.mcc.R.id.itemInputPan); showPanningState(); connection.setInputMode(inputHandler.getName()); connection.save(database.getWritableDatabase()); updateInputMenu(); return true; } return defaultKeyUpHandler(keyCode, evt); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onTouchEvent(android.view.MotionEvent) */ @Override public boolean onTouchEvent(MotionEvent event) { // Mouse Pointer Control Mode // Pointer event is absolute coordinates. vncCanvas.changeTouchCoordinatesToFullFrame(event); if (vncCanvas.processPointerEvent(event, true)) return true; return VncCanvasActivity.super.onTouchEvent(event); } @Override public boolean onGenericMotion(MotionEvent evt) { return false; } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onTrackballEvent(android.view.MotionEvent) */ @Override public boolean onTrackballEvent(MotionEvent evt) { return false; } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#handlerDescription() */ @Override public CharSequence getHandlerDescription() { return getResources().getText(R.string.input_mode_mouse); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#getName() */ @Override public String getName() { return "MOUSE"; } } /** * For hardware mice. */ class HardwareMouseMode extends MouseMode { @Override public boolean onTouchEvent(MotionEvent event) { vncCanvas.changeTouchCoordinatesToFullFrame(event); if (vncCanvas.processPointerEvent(event)) return true; return VncCanvasActivity.super.onTouchEvent(event); } @Override public boolean onGenericMotion(MotionEvent event) { vncCanvas.changeTouchCoordinatesToFullFrame(event); if (vncCanvas.processPointerEvent(event)) return true; return VncCanvasActivity.super.onGenericMotionEvent(event); } @Override public CharSequence getHandlerDescription() { return getString(R.string.input_mode_hardware_mouse); } @Override public String getName() { return "HARDWARE_MOUSE"; } } /** * Touch screen controls, clicks the mouse. DPad pans the screen * * @author Michael A. MacDonald */ class DPadPanTouchMouseMode implements AbstractInputHandler { private boolean isPanning; /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onKeyDown(int, * android.view.KeyEvent) */ @Override public boolean onKeyDown(int keyCode, KeyEvent evt) { int xv = 0; int yv = 0; boolean result = true; switch (keyCode) { case KeyEvent.KEYCODE_DPAD_LEFT: xv = -1; break; case KeyEvent.KEYCODE_DPAD_RIGHT: xv = 1; break; case KeyEvent.KEYCODE_DPAD_UP: yv = -1; break; case KeyEvent.KEYCODE_DPAD_DOWN: yv = 1; break; default: result = defaultKeyDownHandler(keyCode, evt); break; } if ((xv != 0 || yv != 0) && !isPanning) { final int x = xv; final int y = yv; isPanning = true; panner.start(x, y, new Panner.VelocityUpdater() { /* * (non-Javadoc) * * @see android.androidVNC.Panner.VelocityUpdater#updateVelocity(android.graphics.Point, * long) */ @Override public boolean updateVelocity(PointF p, long interval) { double scale = (2.0 * (double) interval / 50.0); if (Math.abs(p.x) < 500) p.x += (int) (scale * x); if (Math.abs(p.y) < 500) p.y += (int) (scale * y); return true; } }); vncCanvas.pan(x, y); } return result; } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onKeyUp(int, * android.view.KeyEvent) */ @Override public boolean onKeyUp(int keyCode, KeyEvent evt) { boolean result = false; switch (keyCode) { case KeyEvent.KEYCODE_DPAD_LEFT: case KeyEvent.KEYCODE_DPAD_RIGHT: case KeyEvent.KEYCODE_DPAD_UP: case KeyEvent.KEYCODE_DPAD_DOWN: panner.stop(); isPanning = false; result = true; break; default: result = defaultKeyUpHandler(keyCode, evt); break; } return result; } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onTouchEvent(android.view.MotionEvent) */ @Override public boolean onTouchEvent(MotionEvent event) { // Mouse Pointer Control Mode // Pointer event is absolute coordinates. vncCanvas.changeTouchCoordinatesToFullFrame(event); if (vncCanvas.processPointerEvent(event, true)) return true; return VncCanvasActivity.super.onTouchEvent(event); } @Override public boolean onGenericMotion(MotionEvent evt) { return false; } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onTrackballEvent(android.view.MotionEvent) */ @Override public boolean onTrackballEvent(MotionEvent evt) { return false; } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#handlerDescription() */ @Override public CharSequence getHandlerDescription() { return getResources().getText(R.string.input_mode_dpad_pan_touchpad_mouse); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#getName() */ @Override public String getName() { return "DPAD_PAN_TOUCH_MOUSE"; } } // Method to start the service for notification icon public void startService() { startService(new Intent(this, MyService.class)); } // Method to stop the service for notification icon public void stopService() { stopService(new Intent(this, MyService.class)); } }