From 452f1d63777894f3e8ca6d84e224738e04ac3a0a Mon Sep 17 00:00:00 2001 From: lihongwei Date: Fri, 27 Jun 2025 13:48:31 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8A=9F=E8=83=BD=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../clicker/autoclicker/data/PointEvent.java | 2 + .../autoclicker/service/AutoClickService.java | 80 +++++++++-- .../autoclicker/util/EventViewBinder.java | 128 ++++++++++++++++-- .../autoclicker/view/FloatingViewManager.java | 22 ++- app/src/main/res/drawable/pause.xml | 9 ++ 5 files changed, 214 insertions(+), 27 deletions(-) create mode 100644 app/src/main/res/drawable/pause.xml diff --git a/app/src/main/java/com/auto/clicker/autoclicker/data/PointEvent.java b/app/src/main/java/com/auto/clicker/autoclicker/data/PointEvent.java index e180cb7..9bbbcbc 100644 --- a/app/src/main/java/com/auto/clicker/autoclicker/data/PointEvent.java +++ b/app/src/main/java/com/auto/clicker/autoclicker/data/PointEvent.java @@ -1,5 +1,6 @@ package com.auto.clicker.autoclicker.data; +import android.util.Log; import android.view.WindowManager; import android.widget.TextView; @@ -31,6 +32,7 @@ public class PointEvent extends Event { } public void setX(int x) { + Log.d("PointEvent", "setX called on id=" + id + " with x=" + x); this.x = x; } diff --git a/app/src/main/java/com/auto/clicker/autoclicker/service/AutoClickService.java b/app/src/main/java/com/auto/clicker/autoclicker/service/AutoClickService.java index eb2b247..ac06164 100644 --- a/app/src/main/java/com/auto/clicker/autoclicker/service/AutoClickService.java +++ b/app/src/main/java/com/auto/clicker/autoclicker/service/AutoClickService.java @@ -12,12 +12,13 @@ import android.view.accessibility.AccessibilityEvent; import androidx.localbroadcastmanager.content.LocalBroadcastManager; - import com.auto.clicker.autoclicker.data.Event; import com.auto.clicker.autoclicker.data.EventWrapper; import com.auto.clicker.autoclicker.data.PointEvent; import com.auto.clicker.autoclicker.data.SlideEvent; +import com.auto.clicker.autoclicker.util.EventViewBinder; import com.auto.clicker.autoclicker.util.ScreenUtils; +import com.auto.clicker.autoclicker.view.FloatingViewManager; import java.util.ArrayList; import java.util.Comparator; @@ -36,6 +37,9 @@ public class AutoClickService extends AccessibilityService { private List runtimeEvents = new ArrayList<>(); + private FloatingViewManager floatingViewManager; + private int touchPointSize; + private final Handler handler = new Handler(Looper.getMainLooper()); private boolean isRunning = false; @@ -52,6 +56,15 @@ public class AutoClickService extends AccessibilityService { int screenWidth = screenSize.x; int screenHeight = screenSize.y; logDebug("屏幕尺寸: " + screenWidth + "x" + screenHeight); + + ForegroundService service = ForegroundService.getInstance(); + if (service != null) { + floatingViewManager = service.getFloatingViewManager(); + } + + if (floatingViewManager != null) { + touchPointSize = floatingViewManager.getTouchPointSize(); + } } public static AutoClickService getInstance() { @@ -118,6 +131,9 @@ public class AutoClickService extends AccessibilityService { isRunning = true; currentEventIndex = 0; + + EventViewBinder.setAllTouchPointsDraggable(false); + logDebug("开始执行事件队列 - 共 " + runtimeEvents.size() + " 个事件"); executeEventsByType(); } @@ -127,6 +143,9 @@ public class AutoClickService extends AccessibilityService { if (isRunning) { isRunning = false; handler.removeCallbacksAndMessages(null); + + EventViewBinder.setAllTouchPointsDraggable(true); + logDebug("停止执行事件"); } } @@ -162,13 +181,20 @@ public class AutoClickService extends AccessibilityService { } private void performSingleClick(PointEvent pointEvent) { - int x = pointEvent.getX(); - int y = pointEvent.getY(); + int viewLeftX = pointEvent.getX(); + int viewTopY = pointEvent.getY(); - logDebug("执行点击: (" + x + ", " + y + ")"); + final int CORRECTION_X = 54; + final int CORRECTION_Y = 165; + + int correctedViewLeftX = viewLeftX + CORRECTION_X; + int correctedViewTopY = viewTopY + CORRECTION_Y; + + int finalClickX = correctedViewLeftX + touchPointSize / 2; + int finalClickY = correctedViewTopY + touchPointSize / 2; Path path = new Path(); - path.moveTo(x, y); + path.moveTo(finalClickX, finalClickY); // 使用最终计算出的点击中心坐标 GestureDescription.StrokeDescription stroke = new GestureDescription.StrokeDescription(path, 0, clickDuration); GestureDescription gesture = @@ -200,16 +226,34 @@ public class AutoClickService extends AccessibilityService { private void performSlide(SlideEvent slideEvent) { PointEvent start = slideEvent.getStartPoint(); PointEvent end = slideEvent.getEndPoint(); - int startX = start.getX(); - int startY = start.getY(); - int endX = end.getX(); - int endY = end.getY(); - logDebug("执行滑动: 从 (" + startX + ", " + startY + ") 到 (" + endX + ", " + endY + ")"); + int viewStartX = start.getX(); + int viewStartY = start.getY(); + int viewEndX = end.getX(); + int viewEndY = end.getY(); + + logDebug("--- performSlide start ---"); + logDebug("原始 SlideEvent 起点: (" + viewStartX + ", " + viewStartY + ")"); + logDebug("原始 SlideEvent 终点: (" + viewEndX + ", " + viewEndY + ")"); + + final int CORRECTION_X = 54; + final int CORRECTION_Y = 165; + + int finalStartX = viewStartX + CORRECTION_X + touchPointSize / 2; + int finalStartY = viewStartY + CORRECTION_Y + touchPointSize / 2; + int finalEndX = viewEndX + CORRECTION_X + touchPointSize / 2; + int finalEndY = viewEndY + CORRECTION_Y + touchPointSize / 2; + + logDebug("滑动起点(视图坐标): (" + viewStartX + ", " + viewStartY + ")"); + logDebug("滑动终点(视图坐标): (" + viewEndX + ", " + viewEndY + ")"); + logDebug("滑动起点(修正后): (" + finalStartX + ", " + finalStartY + ")"); + logDebug("滑动终点(修正后): (" + finalEndX + ", " + finalEndY + ")"); Path path = new Path(); - path.moveTo(startX, startY); - path.lineTo(endX, endY); + // 这里必须使用修正后的坐标,才能确保手势在正确的位置执行 + path.moveTo(finalStartX, finalStartY); + path.lineTo(finalEndX, finalEndY); + GestureDescription.StrokeDescription stroke = new GestureDescription.StrokeDescription(path, 0, slideDuration); GestureDescription gesture = @@ -225,6 +269,10 @@ public class AutoClickService extends AccessibilityService { handler.postDelayed(() -> executeEventsByType(), clickInterval); flashTouchFeedback(feedbackIndex); } + logDebug("--- onCompleted: 下一个事件将是 index " + currentEventIndex + " ---"); + // 再次打印,确认 slideEvent.getStartPoint() 和 getEndPoint() 是否被意外修改 + logDebug("onCompleted 后,SlideEvent 起点: (" + slideEvent.getStartPoint().getX() + ", " + slideEvent.getStartPoint().getY() + ")"); + logDebug("onCompleted 后,SlideEvent 终点: (" + slideEvent.getEndPoint().getX() + ", " + slideEvent.getEndPoint().getY() + ")"); } @Override @@ -234,8 +282,13 @@ public class AutoClickService extends AccessibilityService { currentEventIndex++; handler.postDelayed(() -> executeEventsByType(), clickInterval + 300); } + logDebug("--- onCancelled: 下一个事件将是 index " + currentEventIndex + " ---"); + // 再次打印,确认 slideEvent.getStartPoint() 和 getEndPoint() 是否被意外修改 + logDebug("onCancelled 后,SlideEvent 起点: (" + slideEvent.getStartPoint().getX() + ", " + slideEvent.getStartPoint().getY() + ")"); + logDebug("onCancelled 后,SlideEvent 终点: (" + slideEvent.getEndPoint().getX() + ", " + slideEvent.getEndPoint().getY() + ")"); } }, null); + logDebug("--- performSlide end ---"); } private void flashTouchFeedback(int index) { @@ -257,6 +310,9 @@ public class AutoClickService extends AccessibilityService { super.onDestroy(); instance = null; stopClicking(); + + EventViewBinder.setAllTouchPointsDraggable(true); + Intent intent = new Intent("com.auto.clicker.autoclicker.SERVICE_DESTROYED"); LocalBroadcastManager.getInstance(this).sendBroadcast(intent); logDebug("无障碍服务已销毁"); diff --git a/app/src/main/java/com/auto/clicker/autoclicker/util/EventViewBinder.java b/app/src/main/java/com/auto/clicker/autoclicker/util/EventViewBinder.java index 267d997..9f4991a 100644 --- a/app/src/main/java/com/auto/clicker/autoclicker/util/EventViewBinder.java +++ b/app/src/main/java/com/auto/clicker/autoclicker/util/EventViewBinder.java @@ -7,6 +7,8 @@ import android.os.Build; import android.util.Log; import android.util.TypedValue; import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; import android.view.WindowManager; import android.widget.TextView; @@ -15,19 +17,26 @@ import com.auto.clicker.autoclicker.data.PointEvent; import com.auto.clicker.autoclicker.data.SlideEvent; import com.auto.clicker.autoclicker.view.ConnectingLineView; +import java.util.HashMap; +import java.util.Map; + public class EventViewBinder { + // 存储每个视图及其对应的 OnTouchListener 实例,用于启用/禁用拖动 + private static final Map activeDragListeners = new HashMap<>(); + public interface OnPositionChangedCallback { void onPositionChanged(int x, int y); } + // --- bindPoint 方法 --- public static void bindPoint(Context context, WindowManager windowManager, PointEvent pointEvent, int touchPointSize, int screenWidth, int screenHeight, - OnPositionChangedCallback callback,int order,float initialTextSize) { + OnPositionChangedCallback callback, int order, float initialTextSize) { TextView pointView = createTouchPointView(context, String.valueOf(order)); - Log.d("bind","id: " + order); + Log.d("bind", "id: " + order); WindowManager.LayoutParams params = createTouchPointParams(context, touchPointSize); params.x = pointEvent.getX(); @@ -38,21 +47,26 @@ public class EventViewBinder { pointView.setTextSize(TypedValue.COMPLEX_UNIT_SP, initialTextSize); - DraggableHelper.makeDraggable(pointView, params, windowManager, - screenWidth, screenHeight, + // 创建并保存 OnTouchListener + View.OnTouchListener touchListener = createTouchListener( + pointView, params, windowManager, screenWidth, screenHeight, (x, y) -> { pointEvent.setX(x); pointEvent.setY(y); if (callback != null) callback.onPositionChanged(x, y); }); + pointView.setOnTouchListener(touchListener); + activeDragListeners.put(pointView, touchListener); // 保存监听器到 Map + windowManager.addView(pointView, params); } + // --- bindSlide 方法 --- public static void bindSlide(Context context, WindowManager windowManager, SlideEvent slideEvent, int touchPointSize, int screenWidth, int screenHeight, - OnPositionChangedCallback callback,int order,float initialTextSize) { + OnPositionChangedCallback callback, int order, float initialTextSize) { PointEvent start = slideEvent.getStartPoint(); PointEvent end = slideEvent.getEndPoint(); @@ -81,25 +95,29 @@ public class EventViewBinder { slideEvent.setLineView(lineView); slideEvent.setLineParams(lineParams); - // 拖动起点 - DraggableHelper.makeDraggable(startView, startParams, windowManager, - screenWidth, screenHeight, + // 拖动起点 - 创建并保存监听器 + View.OnTouchListener startTouchListener = createTouchListener( + startView, startParams, windowManager, screenWidth, screenHeight, (x, y) -> { start.setX(x); start.setY(y); updateLinePosition(slideEvent, touchPointSize); if (callback != null) callback.onPositionChanged(x, y); }); + startView.setOnTouchListener(startTouchListener); + activeDragListeners.put(startView, startTouchListener); // 保存监听器 - // 拖动终点 - DraggableHelper.makeDraggable(endView, endParams, windowManager, - screenWidth, screenHeight, + // 拖动终点 - 创建并保存监听器 + View.OnTouchListener endTouchListener = createTouchListener( + endView, endParams, windowManager, screenWidth, screenHeight, (x, y) -> { end.setX(x); end.setY(y); updateLinePosition(slideEvent, touchPointSize); if (callback != null) callback.onPositionChanged(x, y); }); + endView.setOnTouchListener(endTouchListener); + activeDragListeners.put(endView, endTouchListener); // 保存监听器 windowManager.addView(lineView, lineParams); windowManager.addView(startView, startParams); @@ -108,12 +126,95 @@ public class EventViewBinder { updateLinePosition(slideEvent, touchPointSize); } + // --- 从 DraggableHelper 移动过来的 OnTouchListener 创建逻辑 --- + // 这个方法创建并返回一个 View.OnTouchListener 实例 + private static View.OnTouchListener createTouchListener( + View view, WindowManager.LayoutParams params, WindowManager windowManager, + int screenWidth, int screenHeight, DraggableHelper.DragCallback callback) { // 仍然使用 DraggableHelper.DragCallback 接口 + return new View.OnTouchListener() { + private float lastX, lastY; + private float paramX, paramY; + private boolean isDragging = false; // 标记是否正在拖动 + + @Override + public boolean onTouch(View v, MotionEvent event) { + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + lastX = event.getRawX(); + lastY = event.getRawY(); + paramX = params.x; + paramY = params.y; + isDragging = false; // 重置拖动状态 + return true; + + case MotionEvent.ACTION_MOVE: + isDragging = true; // 正在拖动 + float dx = event.getRawX() - lastX; + float dy = event.getRawY() - lastY; + + int newX = (int) (paramX + dx); + int newY = (int) (paramY + dy); + + newX = Math.max(0, Math.min(newX, screenWidth - view.getWidth())); + newY = Math.max(0, Math.min(newY, screenHeight - view.getHeight())); + + params.x = newX; + params.y = newY; + + windowManager.updateViewLayout(view, params); + + if (callback != null) { + callback.onPositionChanged(newX, newY); + } + return true; + + case MotionEvent.ACTION_UP: + if (!isDragging) { // 如果没有拖动,才视为点击 + v.performClick(); + } + return true; + } + return false; + } + }; + } + + // --- 新增方法:统一控制所有触摸点的拖动状态 --- + public static void setAllTouchPointsDraggable(boolean draggable) { + for (Map.Entry entry : activeDragListeners.entrySet()) { + View view = entry.getKey(); + View.OnTouchListener listener = entry.getValue(); + if (draggable) { + // 启用拖动:重新设置保存的监听器 + view.setOnTouchListener(listener); + } else { + // 禁用拖动:将监听器设置为 null,阻止触摸事件 + view.setOnTouchListener(null); + } + } + } + + // --- 新增方法:移除不再需要的视图及其监听器 --- + public static void removeBoundView(WindowManager windowManager, View view) { + if (view != null) { + try { + windowManager.removeView(view); + activeDragListeners.remove(view); // 从 Map 中移除 + Log.d("EventViewBinder", "移除视图并清理监听器: " + view.getTag()); + } catch (IllegalArgumentException e) { + Log.e("EventViewBinder", "尝试移除不存在的视图: " + e.getMessage()); + } + } + } + + // --- 辅助方法 (保持不变) --- public static TextView createTouchPointView(Context context, String label) { TextView touchPointView = new TextView(context); touchPointView.setBackgroundResource(R.drawable.ring_has_bg); touchPointView.setGravity(Gravity.CENTER); touchPointView.setText(label); touchPointView.setTextColor(Color.WHITE); + touchPointView.setTag(label); // 添加一个Tag,方便日志识别 return touchPointView; } @@ -144,7 +245,7 @@ public class EventViewBinder { overlayType, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | - WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, + WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, // 线条通常不可触摸 PixelFormat.TRANSLUCENT ); params.gravity = Gravity.TOP | Gravity.START; @@ -167,5 +268,4 @@ public class EventViewBinder { lineView.setPoints(startCenterX, startCenterY, endCenterX, endCenterY); } -} - +} \ No newline at end of file diff --git a/app/src/main/java/com/auto/clicker/autoclicker/view/FloatingViewManager.java b/app/src/main/java/com/auto/clicker/autoclicker/view/FloatingViewManager.java index e2e5e8e..9a2f15a 100644 --- a/app/src/main/java/com/auto/clicker/autoclicker/view/FloatingViewManager.java +++ b/app/src/main/java/com/auto/clicker/autoclicker/view/FloatingViewManager.java @@ -86,6 +86,8 @@ public class FloatingViewManager { private static final int DEFAULT_TOUCH_POINT_SIZE = 100; private static final int DEFAULT_CONTROL_BAR_WIDTH_DP = 38; + private ImageView playButton; + public FloatingViewManager(Context context) { this.context = context; this.windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); @@ -223,7 +225,7 @@ public class FloatingViewManager { } private void setupControlButtons(LinearLayout controlBar,int mode) { - ImageView playButton = controlBar.findViewById(R.id.play_button); + playButton = controlBar.findViewById(R.id.play_button); ImageView addButton = controlBar.findViewById(R.id.add_button); ImageView removeButton = controlBar.findViewById(R.id.remove_button); ImageView slideButton = controlBar.findViewById(R.id.slide_button); @@ -239,6 +241,10 @@ public class FloatingViewManager { addPointEvent(); } + AutoClickService service = AutoClickService.getInstance(); + boolean serviceIsRunning = (service != null && service.isClicking()); + updatePlayButtonImage(serviceIsRunning); + playButton.setOnClickListener(v -> toggleMultipleClicking()); addButton.setOnClickListener(v -> addPointEvent()); removeButton.setOnClickListener(v -> removeLastEvent()); @@ -286,6 +292,8 @@ public class FloatingViewManager { isMultipleRunning = !isMultipleRunning; Log.d(TAG, "多点点击服务状态: " + service.isClicking()); + + updatePlayButtonImage(isMultipleRunning); } private void addPointEvent() { @@ -906,4 +914,16 @@ public class FloatingViewManager { public int getControlBarWidth() { return controlBarWidth; } + + private void updatePlayButtonImage(boolean isRunning) { + if (playButton == null) { + return; + } + + if (isRunning) { + playButton.setImageResource(R.drawable.pause); + } else { + playButton.setImageResource(R.drawable.play); + } + } } \ No newline at end of file diff --git a/app/src/main/res/drawable/pause.xml b/app/src/main/res/drawable/pause.xml new file mode 100644 index 0000000..3e8e1c6 --- /dev/null +++ b/app/src/main/res/drawable/pause.xml @@ -0,0 +1,9 @@ + + +