package com.javispedro.vndroid; import android.accessibilityservice.AccessibilityService; import android.accessibilityservice.GestureDescription; import android.graphics.Path; import android.os.SystemClock; import android.util.Log; public class PointerEventOutput extends AccessibilityService.GestureResultCallback { private final String TAG = PointerEventOutput.class.getSimpleName(); private void dispatchGesture(GestureDescription gesture) { ControlService service = ControlService.getInstance(); if (service != null) { if (!service.dispatchGesture(gesture, this, null)) { Log.w(TAG, "gesture not dispatched"); } } else { Log.w(TAG, "accessibility service not enabled, cannot control gestures"); } } private void postGlobalAction(int action) { ControlService service = ControlService.getInstance(); if (service != null) { if (!service.performGlobalAction(action)) { Log.w(TAG, "global action not posted"); } } } private long lastTime = 0; private GestureDescription lastGesture = null; private int lastX = -1, lastY = -1; private void pointerGesture(boolean cont, int x, int y, long curTime, boolean willContinue) { Path path = new Path(); long duration = 1; if (cont && lastGesture == null) { Log.w(TAG, "continuing gesture but no previous data"); } if (cont && lastGesture != null) { assert lastX != -1 && lastY != -1; path.moveTo(lastX, lastY); duration = curTime - lastTime; assert duration > 0; } else { path.moveTo(x, y); } path.lineTo(x, y); GestureDescription.Builder builder = new GestureDescription.Builder(); GestureDescription.StrokeDescription stroke; if (cont && lastGesture != null) { stroke = lastGesture.getStroke(0); stroke = stroke.continueStroke(path, 0, duration, willContinue); } else { stroke = new GestureDescription.StrokeDescription(path, 0, duration, willContinue); } builder.addStroke(stroke); GestureDescription gesture = builder.build(); dispatchGesture(gesture); if (willContinue) { lastGesture = gesture; lastTime = curTime; lastX = x; lastY = y; } else { lastGesture = null; lastTime = 0; lastX = -1; lastY = -1; } } private final int BTN_LEFT = 0; private final int BTN_MIDDLE = 1; private final int BTN_RIGHT = 2; private byte prevButtonMask = 0; private boolean buttonPressed(byte mask, int btn) { return (mask & (1 << btn)) != 0; } public void postPointerEvent(byte buttonMask, int x, int y) { final long curTime = SystemClock.uptimeMillis(); if (buttonPressed(buttonMask, BTN_LEFT)) { // Main button pressed if (!buttonPressed(prevButtonMask, BTN_LEFT)) { pointerGesture(false, x, y, curTime, true); } else { // Button moved while pressed pointerGesture(true, x, y, curTime, true); } } else if (buttonPressed(prevButtonMask, BTN_LEFT)) { // Button was pressed but now released pointerGesture(true, x, y, curTime, false); } if (buttonPressed(buttonMask, BTN_RIGHT) && !buttonPressed(prevButtonMask, BTN_RIGHT)) { postGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK); } prevButtonMask = buttonMask; } @Override public void onCompleted(GestureDescription gestureDescription) { } @Override public void onCancelled(GestureDescription gestureDescription) { Log.d(TAG, "gesture cancelled"); } }