package com.javispedro.vndroid; import android.app.Activity; import android.app.Notification; import android.app.Service; import android.content.Intent; import android.content.res.Configuration; import android.media.Image; import android.media.projection.MediaProjection; import android.media.projection.MediaProjectionManager; import android.os.IBinder; import android.util.Log; import android.view.WindowManager; import android.widget.Toast; import com.javispedro.vndroid.keymaps.AndroidKeyHandler; import com.javispedro.vndroid.keymaps.SpanishKeyHandler; public class ServerService extends Service { private static final String TAG = ServerService.class.getSimpleName(); public static final String ACTION_START = "ACTION_START"; public static final String ACTION_STOP = "ACTION_STOP"; public static final String ACTION_NOTIFY_MEDIA_PROJECTION_RESULT = "ACTION_NOTIFY_MEDIA_PROJECTION_RESULT"; private ScreenGrabber screenGrabber; private RFBServer rfbServer; private PointerEventOutput pointerOut; private KeyEventOutput keyOut; public ServerService() { } @Override public void onCreate() { ServerRunningNotification.initNotificationChannel(this); System.loadLibrary("native-lib"); } @Override public IBinder onBind(Intent intent) { throw new UnsupportedOperationException("Not implemented"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { if (intent != null) { switch (intent.getAction()) { case ACTION_START: start(); break; case ACTION_STOP: stop(); break; case ACTION_NOTIFY_MEDIA_PROJECTION_RESULT: notifyMediaProjectionResult(intent.getIntExtra("resultCode", Activity.RESULT_CANCELED), (Intent) intent.getParcelableExtra("resultData")); break; } } return super.onStartCommand(intent, flags, startId); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); if (screenGrabber != null && screenGrabber.hasSizeChanged()) { Log.d(TAG, "screen size has changed"); screenGrabber.updateScreenSize(); } } protected class ScreenGrabberCallback implements ScreenGrabber.Callback { @Override public void onImage(Image image) { if (rfbServer != null) { rfbServer.putImage(image); } else { image.close(); } } } protected class EventCallback implements RFBServer.EventCallback { @Override public void onPointerEvent(int buttonMask, int x, int y) { try { x = screenGrabber.scaleInputX(x); y = screenGrabber.scaleInputY(y); pointerOut.postPointerEvent((byte) buttonMask, x, y); } catch (Exception e) { Log.e(TAG, "Exception on pointer EventCallback: " + e.toString()); e.printStackTrace(); // Need to supress the exception, otherwise we'll crash JNI } } @Override public void onKeyEvent(int key, boolean state) { try { keyOut.postKeyEvent(key, state); } catch (Exception e) { Log.e(TAG, "Exception on key EventCallback: " + e.toString()); e.printStackTrace(); } } } protected void start() { if (rfbServer != null) { Log.w(TAG, "cannot start, already started"); return; } Log.d(TAG, "starting"); if (!ControlService.isServiceStarted()) { Toast toast = Toast.makeText(this, R.string.toast_no_input_service, Toast.LENGTH_SHORT); toast.show(); } pointerOut = new PointerEventOutput(); keyOut = new KeyEventOutput(); keyOut.addHandler(new AndroidKeyHandler()); keyOut.addHandler(new SpanishKeyHandler()); if (screenGrabber == null) { screenGrabber = new ScreenVirtualGrabber(this); } rfbServer = new RFBServer(); rfbServer.setEventCallback(new EventCallback()); rfbServer.start(); screenGrabber.setCallback(new ScreenGrabberCallback()); screenGrabber.start(); Notification notification = ServerRunningNotification.build(this); startForeground(1, notification); } protected void stop() { Log.d(TAG, "stopping"); if (rfbServer != null) { rfbServer.stop(); rfbServer = null; } if (screenGrabber != null) { screenGrabber.stop(); screenGrabber = null; } if (pointerOut != null) { pointerOut = null; } if (keyOut != null) { keyOut = null; } stopForeground(true); stopSelf(); } protected void notifyMediaProjectionResult(int resultCode, Intent data) { if (screenGrabber != null) { Log.w(TAG, "already have an screen grabber"); } MediaProjectionManager manager = getSystemService(MediaProjectionManager.class); MediaProjection projection = manager.getMediaProjection(resultCode, data); WindowManager wm = getSystemService(WindowManager.class); screenGrabber = new ScreenMirrorGrabber(this, projection, wm.getDefaultDisplay()); } }