优化现有实现

This commit is contained in:
lihongwei 2025-05-06 14:15:16 +08:00
parent 9643d74864
commit c7d8087b3e
14 changed files with 547 additions and 830 deletions

View File

@ -12,10 +12,14 @@ import android.view.accessibility.AccessibilityEvent;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import com.auto.autoclicker.data.Event;
import com.auto.autoclicker.data.EventWrapper;
import com.auto.autoclicker.data.PointEvent;
import com.auto.autoclicker.data.SlideEvent;
import com.auto.autoclicker.util.ScreenUtils;
import com.auto.autoclicker.util.ViewUtils;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class AutoClickService extends AccessibilityService {
@ -29,15 +33,14 @@ public class AutoClickService extends AccessibilityService {
private static final int MIN_SLIDE_DURATION = 100;
private static final int MAX_SLIDE_DURATION = 2000;
private final List<Event> eventQueue = new ArrayList<>();
private List<EventWrapper> runtimeEvents = new ArrayList<>();
private final Handler handler = new Handler(Looper.getMainLooper());
private boolean isRunning = false;
private long clickInterval = 1000;
private int clickDuration = 200;
private int slideDuration = 500;
private int screenWidth;
private int screenHeight;
private int currentEventIndex = 0;
@Override
@ -45,8 +48,8 @@ public class AutoClickService extends AccessibilityService {
super.onCreate();
instance = this;
Point screenSize = ScreenUtils.getScreenSize(this);
screenWidth = screenSize.x;
screenHeight = screenSize.y;
int screenWidth = screenSize.x;
int screenHeight = screenSize.y;
logDebug("屏幕尺寸: " + screenWidth + "x" + screenHeight);
}
@ -66,50 +69,16 @@ public class AutoClickService extends AccessibilityService {
logDebug("无障碍服务中断");
}
public void setClickPosition(float x, float y) {
Point constrained = ViewUtils.constrainToScreen(x, y, screenWidth, screenHeight);
clearEvents();
eventQueue.add(new ClickEvent(constrained.x, constrained.y, -1));
logDebug("设置单点点击位置: 原始 (" + x + ", " + y + ") -> 修正 (" + constrained.x + ", " + constrained.y + ")");
}
public void clearEvents() {
eventQueue.clear();
runtimeEvents.clear();
logDebug("清除所有事件");
}
public void addClickEvent(int x, int y, int index) {
Point constrained = ViewUtils.constrainToScreen(x, y, screenWidth, screenHeight);
eventQueue.add(new ClickEvent(constrained.x, constrained.y, index));
logDebug("添加点击事件 #" + index + ": (" + constrained.x + ", " + constrained.y + ")");
}
public void addMultipleClickEvents(List<Point> positions) {
public void addMultipleClickEvents(List<EventWrapper> eventWrapperList) {
clearEvents();
for (int i = 0; i < positions.size(); i++) {
Point p = positions.get(i);
addClickEvent(p.x, p.y, i);
}
logDebug("设置多点点击事件: " + positions.size() + " 个点");
}
public void addSlideEvent(int startX, int startY, int endX, int endY) {
Point constrainedStart = ViewUtils.constrainToScreen(startX, startY, screenWidth, screenHeight);
Point constrainedEnd = ViewUtils.constrainToScreen(endX, endY, screenWidth, screenHeight);
eventQueue.add(new SlideMultipleEvent(
constrainedStart.x, constrainedStart.y,
constrainedEnd.x, constrainedEnd.y));
logDebug("添加滑动事件: 从 (" + constrainedStart.x + ", " + constrainedStart.y +
") 到 (" + constrainedEnd.x + ", " + constrainedEnd.y + ")");
}
public void addMultipleSlideEvents(List<Slide> slides) {
for (Slide slide : slides) {
addSlideEvent(slide.startX, slide.startY, slide.endX, slide.endY);
}
logDebug("添加多个滑动事件: " + slides.size() + "");
runtimeEvents = new ArrayList<>(eventWrapperList);
logDebug("设置多点点击事件: " + eventWrapperList.size() + " 个点");
}
public void setClickInterval(long interval) {
@ -141,15 +110,15 @@ public class AutoClickService extends AccessibilityService {
public void startClicking() {
if (!isRunning) {
if (eventQueue.isEmpty()) {
if (runtimeEvents.isEmpty()) {
Log.w(TAG, "无事件队列,忽略开始");
return;
}
isRunning = true;
currentEventIndex = 0;
logDebug("开始执行事件队列 - 共 " + eventQueue.size() + " 个事件");
executeNextEvent();
logDebug("开始执行事件队列 - 共 " + runtimeEvents.size() + " 个事件");
executeEventsByType();
}
}
@ -165,46 +134,40 @@ public class AutoClickService extends AccessibilityService {
return isRunning;
}
private void executeNextEvent() {
if (!isRunning || eventQueue.isEmpty()) {
private void executeEventsByType() {
if (!isRunning || runtimeEvents.isEmpty()) {
logDebug("跳过执行:服务未运行或事件队列为空");
return;
}
Event event = eventQueue.get(currentEventIndex);
runtimeEvents.sort(Comparator.comparingInt(EventWrapper::getOrder));
if (event instanceof ClickEvent) {
ClickEvent clickEvent = (ClickEvent) event;
logDebug("即将执行点击事件: (" + clickEvent.getX() + ", " + clickEvent.getY() + "), index=" + clickEvent.getAdditionalInfo());
} else if (event instanceof SlideMultipleEvent) {
SlideMultipleEvent slideMultipleEvent = (SlideMultipleEvent) event;
logDebug("即将执行滑动事件: 从 (" + slideMultipleEvent.startX + ", " + slideMultipleEvent.startY + ") 到 (" + slideMultipleEvent.endX + ", " + slideMultipleEvent.endY + ")");
} else {
logDebug("未知事件类型: " + event.getClass().getSimpleName());
if (currentEventIndex >= runtimeEvents.size()) {
currentEventIndex = 0;
}
if (event instanceof ClickEvent) {
ClickEvent clickEvent = (ClickEvent) event;
Point clickPoint = new Point(clickEvent.getX(), clickEvent.getY());
performSingleClick(clickPoint, clickEvent.getAdditionalInfo());
} else if (event instanceof SlideMultipleEvent) {
SlideMultipleEvent slideMultipleEvent = (SlideMultipleEvent) event;
performSlide(slideMultipleEvent);
} else {
logDebug("未知事件类型,跳过执行: " + event.getClass().getSimpleName());
// 也可以选择继续执行下一个
handler.postDelayed(this::executeNextEvent, clickInterval);
}
EventWrapper wrapper = runtimeEvents.get(currentEventIndex);
Event event = wrapper.getEvent();
// 准备下一个事件
currentEventIndex = (currentEventIndex + 1) % eventQueue.size();
if (wrapper.getType() == EventWrapper.EventType.POINT && event instanceof PointEvent) {
performSingleClick((PointEvent) event);
} else if (wrapper.getType() == EventWrapper.EventType.SLIDE && event instanceof SlideEvent) {
performSlide((SlideEvent) event);
} else {
logDebug("未知或不匹配的事件类型,跳过执行: " + wrapper.getType());
currentEventIndex++;
handler.postDelayed(this::executeEventsByType, clickInterval);
}
}
private void performSingleClick(Point clickPoint, int index) {
logDebug("执行点击: (" + clickPoint.x + ", " + clickPoint.y + ")");
private void performSingleClick(PointEvent pointEvent) {
int x = pointEvent.getX();
int y = pointEvent.getY();
logDebug("执行点击: (" + x + ", " + y + ")");
Path path = new Path();
path.moveTo(clickPoint.x, clickPoint.y);
path.moveTo(x, y);
GestureDescription.StrokeDescription stroke =
new GestureDescription.StrokeDescription(path, 0, clickDuration);
GestureDescription gesture =
@ -215,8 +178,10 @@ public class AutoClickService extends AccessibilityService {
public void onCompleted(GestureDescription gestureDescription) {
logDebug("点击完成");
if (isRunning) {
handler.postDelayed(() -> executeNextEvent(), clickInterval);
flashTouchFeedback(index);
int feedbackIndex = currentEventIndex;
currentEventIndex++;
handler.postDelayed(() -> executeEventsByType(), clickInterval);
flashTouchFeedback(feedbackIndex);
}
}
@ -224,19 +189,26 @@ public class AutoClickService extends AccessibilityService {
public void onCancelled(GestureDescription gestureDescription) {
Log.e(TAG, "点击被取消");
if (isRunning) {
handler.postDelayed(() -> executeNextEvent(), clickInterval + 300);
currentEventIndex++;
handler.postDelayed(() -> executeEventsByType(), clickInterval + 300);
}
}
}, null);
}
private void performSlide(SlideMultipleEvent slide) {
logDebug("执行滑动: 从 (" + slide.startX + ", " + slide.startY +
") 到 (" + slide.endX + ", " + slide.endY + ")");
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 + ")");
Path path = new Path();
path.moveTo(slide.startX, slide.startY);
path.lineTo(slide.endX, slide.endY);
path.moveTo(startX, startY);
path.lineTo(endX, endY);
GestureDescription.StrokeDescription stroke =
new GestureDescription.StrokeDescription(path, 0, slideDuration);
GestureDescription gesture =
@ -247,7 +219,10 @@ public class AutoClickService extends AccessibilityService {
public void onCompleted(GestureDescription gestureDescription) {
logDebug("滑动完成");
if (isRunning) {
handler.postDelayed(() -> executeNextEvent(), clickInterval);
int feedbackIndex = currentEventIndex;
currentEventIndex++;
handler.postDelayed(() -> executeEventsByType(), clickInterval);
flashTouchFeedback(feedbackIndex);
}
}
@ -255,7 +230,8 @@ public class AutoClickService extends AccessibilityService {
public void onCancelled(GestureDescription gestureDescription) {
Log.e(TAG, "滑动被取消");
if (isRunning) {
handler.postDelayed(() -> executeNextEvent(), clickInterval + 300);
currentEventIndex++;
handler.postDelayed(() -> executeEventsByType(), clickInterval + 300);
}
}
}, null);

View File

@ -1,19 +0,0 @@
package com.auto.autoclicker;
public class ClickEvent extends Event {
private int additionalInfo;
public ClickEvent(int x, int y, int additionalInfo) {
super(additionalInfo, x, y);
this.additionalInfo = additionalInfo;
}
public int getAdditionalInfo() {
return additionalInfo;
}
public void setAdditionalInfo(int additionalInfo) {
this.additionalInfo = additionalInfo;
}
}

View File

@ -1,26 +0,0 @@
package com.auto.autoclicker;
public class Event {
protected int id;
protected int x;
protected int y;
public Event(int id, int x, int y) {
this.id = id;
this.x = x;
this.y = y;
}
// Getter 方法
public int getId() {
return id;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}

View File

@ -64,7 +64,6 @@ public class ForegroundService extends Service {
return START_STICKY;
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(

View File

@ -1,31 +0,0 @@
package com.auto.autoclicker;
import android.view.WindowManager;
import android.widget.TextView;
public class PointEvent extends Event {
private TextView view;
private WindowManager.LayoutParams params;
public PointEvent(int id, int x, int y, TextView view, WindowManager.LayoutParams params) {
super(id, x, y);
this.view = view;
this.params = params;
}
public TextView getView() {
return view;
}
public WindowManager.LayoutParams getParams() {
return params;
}
public void setView(TextView view) {
this.view = view;
}
public void setParams(WindowManager.LayoutParams params) {
this.params = params;
}
}

View File

@ -1,16 +0,0 @@
package com.auto.autoclicker;
public class Slide {
public final int startX;
public final int startY;
public final int endX;
public final int endY;
public Slide(int startX, int startY, int endX, int endY) {
this.startX = startX;
this.startY = startY;
this.endX = endX;
this.endY = endY;
}
}

View File

@ -1,26 +0,0 @@
package com.auto.autoclicker;
public class SlideMultipleEvent extends Event {
public int startX;
public int startY;
public int endX;
public int endY;
public SlideMultipleEvent(int startX, int startY, int endX, int endY) {
super(-1, startX, startY);
this.startX = startX;
this.startY = startY;
this.endX = endX;
this.endY = endY;
}
public SlideMultipleEvent(int id, int startX, int startY, int endX, int endY) {
super(id, startX, startY);
this.startX = startX;
this.startY = startY;
this.endX = endX;
this.endY = endY;
}
}

View File

@ -0,0 +1,13 @@
package com.auto.autoclicker.data;
public abstract class Event {
protected int id;
public Event(int id) {
this.id = id;
}
public int getId() {
return id;
}
}

View File

@ -0,0 +1,40 @@
package com.auto.autoclicker.data;
public class EventWrapper {
public enum EventType { POINT, SLIDE }
private EventType type;
private Event event;
private int order; // 添加顺序编号用于UI编号
public EventWrapper(EventType type, Event event, int order) {
this.type = type;
this.event = event;
this.order = order;
}
public EventType getType() {
return type;
}
public void setType(EventType type) {
this.type = type;
}
public Event getEvent() {
return event;
}
public void setEvent(Event event) {
this.event = event;
}
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
}

View File

@ -0,0 +1,52 @@
package com.auto.autoclicker.data;
import android.view.View;
import android.view.WindowManager;
import android.widget.TextView;
public class PointEvent extends Event {
private int x;
private int y;
private TextView view; // 悬浮窗上的控件
private WindowManager.LayoutParams layoutParams;
public PointEvent(int id, int x, int y, TextView view, WindowManager.LayoutParams layoutParams) {
super(id);
this.x = x;
this.y = y;
this.view = view;
this.layoutParams = layoutParams;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public View getView() {
return view;
}
public void setView(TextView view) {
this.view = view;
}
public WindowManager.LayoutParams getLayoutParams() {
return layoutParams;
}
public void setLayoutParams(WindowManager.LayoutParams layoutParams) {
this.layoutParams = layoutParams;
}
}

View File

@ -0,0 +1,5 @@
package com.auto.autoclicker.data;
public interface PositionUpdater {
void update(float paramX, float paramY, float dx, float dy);
}

View File

@ -1,16 +1,19 @@
package com.auto.autoclicker;
package com.auto.autoclicker.data;
import android.view.WindowManager;
import com.auto.autoclicker.ConnectingLineView;
public class SlideEvent extends Event {
private PointEvent startPoint;
private PointEvent endPoint;
private ConnectingLineView lineView;
private WindowManager.LayoutParams lineParams;
private long durationMillis; // 滑动时间
public SlideEvent(int id, PointEvent startPoint, PointEvent endPoint,
ConnectingLineView lineView, WindowManager.LayoutParams lineParams) {
super(id, 0, 0);
super(id);
this.startPoint = startPoint;
this.endPoint = endPoint;
this.lineView = lineView;
@ -21,32 +24,39 @@ public class SlideEvent extends Event {
return startPoint;
}
public PointEvent getEndPoint() {
return endPoint;
}
public ConnectingLineView getLineView() {
return lineView;
}
public WindowManager.LayoutParams getLineParams() {
return lineParams;
}
public void setStartPoint(PointEvent startPoint) {
this.startPoint = startPoint;
}
public PointEvent getEndPoint() {
return endPoint;
}
public void setEndPoint(PointEvent endPoint) {
this.endPoint = endPoint;
}
public ConnectingLineView getLineView() {
return lineView;
}
public void setLineView(ConnectingLineView lineView) {
this.lineView = lineView;
}
public WindowManager.LayoutParams getLineParams() {
return lineParams;
}
public void setLineParams(WindowManager.LayoutParams lineParams) {
this.lineParams = lineParams;
}
}
public long getDurationMillis() {
return durationMillis;
}
public void setDurationMillis(long durationMillis) {
this.durationMillis = durationMillis;
}
}

View File

@ -1,45 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/rounded_background"
android:gravity="center"
android:orientation="vertical"
android:padding="8dp">
<ImageView
android:id="@+id/play_button"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginBottom="8dp"
android:src="@drawable/play" />
<ImageView
android:id="@+id/file_button"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginBottom="8dp"
android:src="@drawable/save" />
<ImageView
android:id="@+id/eye_button"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginBottom="8dp"
android:src="@drawable/eye" />
<ImageView
android:id="@+id/settings_button"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginBottom="8dp"
android:src="@drawable/setting" />
<ImageView
android:id="@+id/close_button"
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/cancel" />
</LinearLayout>