diff --git a/app/src/main/java/com/auto/autoclicker/AutoClickService.java b/app/src/main/java/com/auto/autoclicker/AutoClickService.java index f80e14b..747ef06 100644 --- a/app/src/main/java/com/auto/autoclicker/AutoClickService.java +++ b/app/src/main/java/com/auto/autoclicker/AutoClickService.java @@ -19,12 +19,10 @@ import java.util.ArrayList; import java.util.List; public class AutoClickService extends AccessibilityService { - private final List multiClickPoints = new ArrayList<>(); - private static final String TAG = "AutoClickService"; private static AutoClickService instance; - private final List multiClickPositions = new ArrayList<>(); + private final List moreClickPositions = new ArrayList<>(); private int currentClickIndex = 0; private static final long MIN_CLICK_INTERVAL = 40; @@ -70,14 +68,15 @@ public class AutoClickService extends AccessibilityService { public void setClickPosition(float x, float y) { Point constrained = ViewUtils.constrainToScreen(x, y, screenWidth, screenHeight); + this.moreClickPositions.clear(); this.clickX = constrained.x; this.clickY = constrained.y; logDebug("设置单点点击位置: 原始 (" + x + ", " + y + ") -> 修正 (" + clickX + ", " + clickY + ")"); } - public void setMultiClickPositions(List positions) { - this.multiClickPositions.clear(); - this.multiClickPositions.addAll(positions); + public void setMoreClickPositions(List positions) { + this.moreClickPositions.clear(); + this.moreClickPositions.addAll(positions); logDebug("设置多点点击位置: " + positions.size() + " 个点"); } @@ -101,10 +100,11 @@ public class AutoClickService extends AccessibilityService { public void startClicking() { if (!isClicking) { - if (multiClickPositions.isEmpty() && (clickX == 0 && clickY == 0)) { + if (moreClickPositions.isEmpty() && (clickX == 0 && clickY == 0)) { Log.w(TAG, "无有效点击位置,忽略开始点击"); return; } + isClicking = true; currentClickIndex = 0; logDebug("开始自动点击"); @@ -130,19 +130,20 @@ public class AutoClickService extends AccessibilityService { return; } - // 决定使用单点还是多点点击 Point clickPoint; - if (!multiClickPositions.isEmpty()) { - // 多点点击模式 - clickPoint = multiClickPositions.get(currentClickIndex); - currentClickIndex = (currentClickIndex + 1) % multiClickPositions.size(); + int flashIndex = -1; // 新增变量,控制闪烁哪个点 + + if (!moreClickPositions.isEmpty()) { + // 多点模式:取当前索引的点 + clickPoint = moreClickPositions.get(currentClickIndex); + flashIndex = currentClickIndex; // 标记当前点击的是第几个点 } else { - // 单点点击模式 + // 单点模式 clickPoint = new Point(clickX, clickY); } logDebug("执行点击: (" + clickPoint.x + ", " + clickPoint.y + ")"); - flashTouchFeedback(); + flashTouchFeedback(flashIndex); Path path = new Path(); path.moveTo(clickPoint.x, clickPoint.y); @@ -155,7 +156,14 @@ public class AutoClickService extends AccessibilityService { @Override public void onCompleted(GestureDescription gestureDescription) { logDebug("点击完成"); + if (isClicking) { + if (!moreClickPositions.isEmpty()) { + // 多点模式:下一个触摸点 + currentClickIndex = (currentClickIndex + 1) % moreClickPositions.size(); + logDebug("当前点击点" + currentClickIndex); + } + // 安排下一次点击(无论是单点还是多点) handler.postDelayed(() -> performClick(), clickInterval); } } @@ -163,15 +171,21 @@ public class AutoClickService extends AccessibilityService { @Override public void onCancelled(GestureDescription gestureDescription) { Log.e(TAG, "点击被取消"); + if (isClicking) { + if (!moreClickPositions.isEmpty()) { + currentClickIndex = (currentClickIndex + 1) % moreClickPositions.size(); + } + // 点击取消也继续循环 handler.postDelayed(() -> performClick(), clickInterval + 300); } } }, null); } - private void flashTouchFeedback() { + private void flashTouchFeedback(int index) { Intent intent = new Intent("com.auto.autoclicker.FLASH_TOUCH_POINT"); + intent.putExtra("index", index); // 带上当前点击点的index LocalBroadcastManager.getInstance(this).sendBroadcast(intent); } diff --git a/app/src/main/java/com/auto/autoclicker/FloatingViewManager.java b/app/src/main/java/com/auto/autoclicker/FloatingViewManager.java index c1505fc..bade7ac 100644 --- a/app/src/main/java/com/auto/autoclicker/FloatingViewManager.java +++ b/app/src/main/java/com/auto/autoclicker/FloatingViewManager.java @@ -54,11 +54,12 @@ public class FloatingViewManager { private WindowManager.LayoutParams singleControlBarParams; private WindowManager.LayoutParams moreControlBarParams; + private boolean isMoreClicking = false; + private float touchPointX = 500; private float touchPointY = 500; private boolean isClicking = false; - private boolean isFloatingViewsShown = false; private long lastToggleTime = 0; @@ -80,7 +81,8 @@ public class FloatingViewManager { @Override public void onReceive(Context context, Intent intent) { if ("com.auto.autoclicker.FLASH_TOUCH_POINT".equals(intent.getAction())) { - flashTouchPoint(); + int index = intent.getIntExtra("index", -1); // 默认是-1 + flashTouchPoint(index); } } }, new IntentFilter("com.auto.autoclicker.FLASH_TOUCH_POINT")); @@ -108,21 +110,11 @@ public class FloatingViewManager { initMoreTouchPointView(); initMoreControlBar(); - if (moreTouchPointViews.size() == moreTouchPointParams.size()) { - for (int i = 0; i < moreTouchPointViews.size(); i++) { - windowManager.addView(moreTouchPointViews.get(i), moreTouchPointParams.get(i)); - } - } else { - Log.e(TAG, "触摸点与布局参数数量不一致"); - } - - if (moreControlBarView != null) { windowManager.addView(moreControlBarView, moreControlBarParams); } } - isFloatingViewsShown = true; logDebug("悬浮窗已添加,模式 = " + mode); } @@ -161,7 +153,7 @@ public class FloatingViewManager { updateTouchPointPosition(paramX, paramY, dx, dy); AutoClickService service = AutoClickService.getInstance(); if (service != null) { - service.setClickPosition(touchPointX + 50, touchPointY + 50); + service.setClickPosition(touchPointX, touchPointY); logDebug("单点触摸点移动到: (" + touchPointX + ", " + touchPointY + ")"); } break; @@ -174,7 +166,6 @@ public class FloatingViewManager { private void initMoreTouchPointView() { moreTouchPointViews.clear(); moreTouchPointParams.clear(); - addNewTouchPoint(100, 500); } @SuppressLint("ClickableViewAccessibility") @@ -272,15 +263,17 @@ public class FloatingViewManager { } }); + ImageView playButton = moreControlBarView.findViewById(R.id.play_button); ImageView addButton = moreControlBarView.findViewById(R.id.add_button); ImageView removeButton = moreControlBarView.findViewById(R.id.remove_button); - ImageView playButton = moreControlBarView.findViewById(R.id.play_button); + ImageView slideButton = moreControlBarView.findViewById(R.id.slide_button); ImageView closeButton = moreControlBarView.findViewById(R.id.close_button); ImageView settingButton = moreControlBarView.findViewById(R.id.settings_button); - addButton.setOnClickListener(v -> addNewTouchPoint(100 + moreTouchPointViews.size() * 120, 500)); - removeButton.setOnClickListener(v -> removeLastTouchPoint()); - playButton.setOnClickListener(v -> toggleMoreClicking(playButton)); + playButton.setOnClickListener(v -> toggleMoreClicking()); + addButton.setOnClickListener(v -> addMoreTouchPoint()); + removeButton.setOnClickListener(v -> removeMoreTouchPoint()); + closeButton.setOnClickListener(v -> closeFloatingViews()); settingButton.setOnClickListener(v -> showInputDialog()); } @@ -304,7 +297,7 @@ public class FloatingViewManager { singleTouchPointView.setBackgroundResource(R.drawable.un_touch_point); Toast.makeText(context, "停止自动点击", Toast.LENGTH_SHORT).show(); } else { - service.setClickPosition(touchPointX + 50, touchPointY + 50); + service.setClickPosition(touchPointX, touchPointY); service.startClicking(); play.setBackgroundResource(R.drawable.pause); singleTouchPointView.setBackgroundResource(R.drawable.touch_point); @@ -315,44 +308,6 @@ public class FloatingViewManager { logDebug("单点服务是否点击中: " + service.isClicking()); } - private void toggleMoreClicking(ImageView play) { - if (isDebounced()) return; - - AutoClickService service = AutoClickService.getInstance(); - if (service == null) { - Log.e(TAG, "AutoClickService 未初始化"); - Toast.makeText(context, "请在设置中启用无障碍服务", Toast.LENGTH_LONG).show(); - Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(intent); - return; - } - - if (isClicking) { - service.stopClicking(); - play.setBackgroundResource(R.drawable.play); - for (View point : moreTouchPointViews) { - point.setBackgroundResource(R.drawable.un_touch_point); - } - Toast.makeText(context, "停止多点自动点击", Toast.LENGTH_SHORT).show(); - } else { - List positions = new ArrayList<>(); - for (WindowManager.LayoutParams params : moreTouchPointParams) { - positions.add(new Point(params.x + 50, params.y + 50)); - } - service.setMultiClickPositions(positions); - service.startClicking(); - play.setBackgroundResource(R.drawable.pause); - for (View point : moreTouchPointViews) { - point.setBackgroundResource(R.drawable.touch_point); - } - Toast.makeText(context, "开始多点自动点击", Toast.LENGTH_SHORT).show(); - } - - isClicking = !isClicking; - logDebug("多点服务是否点击中: " + service.isClicking()); - } - private void closeFloatingViews() { AutoClickService service = AutoClickService.getInstance(); if (service != null) { @@ -379,6 +334,125 @@ public class FloatingViewManager { LocalBroadcastManager.getInstance(context).sendBroadcast(intent); } + private void toggleMoreClicking() { + if (isDebounced()) return; + + AutoClickService service = AutoClickService.getInstance(); + if (service == null) { + Log.e(TAG, "AutoClickService 未初始化"); + Toast.makeText(context, "请在设置中启用无障碍服务", Toast.LENGTH_LONG).show(); + Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + return; + } + + if (moreTouchPointViews.isEmpty()) { + Toast.makeText(context, "请先添加触摸点", Toast.LENGTH_SHORT).show(); + return; + } + + if (isMoreClicking) { + service.stopClicking(); + Toast.makeText(context, "停止多点点击", Toast.LENGTH_SHORT).show(); + } else { + service.setMoreClickPositions(getMoreTouchPositions()); + service.startClicking(); + Toast.makeText(context, "开始多点点击", Toast.LENGTH_SHORT).show(); + } + + isMoreClicking = !isMoreClicking; + logDebug("多点服务是否点击中: " + service.isClicking()); + } + + private void addMoreTouchPoint() { + View point = new View(context); + point.setBackgroundResource(R.drawable.un_touch_point); + + WindowManager.LayoutParams params = new WindowManager.LayoutParams( + 100, 100, + Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? + WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY : + WindowManager.LayoutParams.TYPE_PHONE, + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | + WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, + PixelFormat.TRANSLUCENT + ); + + params.gravity = Gravity.TOP | Gravity.START; + params.x = screenWidth / 2 - 50; + params.y = screenHeight / 2 - 50; + + point.setOnTouchListener(new View.OnTouchListener() { + private float lastX, lastY; + private float paramX, paramY; + + @Override + public boolean onTouch(View v, MotionEvent event) { + int index = moreTouchPointViews.indexOf(v); // 获取当前触摸点索引 + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + lastX = event.getRawX(); + lastY = event.getRawY(); + paramX = params.x; + paramY = params.y; + return true; + case MotionEvent.ACTION_MOVE: + float dx = event.getRawX() - lastX; + float dy = event.getRawY() - lastY; + Point constrainedPoint = ViewUtils.constrainToScreen( + paramX + dx, paramY + dy, + screenWidth - point.getWidth(), screenHeight - point.getHeight()); + params.x = constrainedPoint.x; + params.y = constrainedPoint.y; + windowManager.updateViewLayout(point, params); + + // 更新 moreTouchPointParams + if (index >= 0 && index < moreTouchPointParams.size()) { + moreTouchPointParams.set(index, params); + } + + // 收集所有触摸点位置 + List points = new ArrayList<>(); + for (WindowManager.LayoutParams p : moreTouchPointParams) { + points.add(new Point(p.x, p.y)); + } + + // 更新 AutoClickService 的 moreClickPositions + AutoClickService service = AutoClickService.getInstance(); + if (service != null) { + service.setMoreClickPositions(points); + } + + return true; + case MotionEvent.ACTION_UP: + v.performClick(); + return true; + } + return false; + } + }); + + windowManager.addView(point, params); + moreTouchPointViews.add(point); + moreTouchPointParams.add(params); + } + + private void removeMoreTouchPoint() { + if (!moreTouchPointViews.isEmpty()) { + View lastPoint = moreTouchPointViews.get(moreTouchPointViews.size() - 1); + try { + windowManager.removeView(lastPoint); + } catch (Exception e) { + Log.w(TAG, "移除 touchPoint 失败", e); + } + moreTouchPointViews.remove(moreTouchPointViews.size() - 1); + moreTouchPointParams.remove(moreTouchPointParams.size() - 1); + } else { + Toast.makeText(context, "没有更多触摸点可以删除", Toast.LENGTH_SHORT).show(); + } + } + public void removeFloatingViews() { try { // 移除单点触摸视图 @@ -423,77 +497,14 @@ public class FloatingViewManager { moreControlBarView = null; } - isFloatingViewsShown = false; isClicking = false; logDebug("悬浮窗已移除"); } catch (Exception e) { Log.e(TAG, "移除悬浮窗失败", e); - isFloatingViewsShown = false; isClicking = false; } } - private void addNewTouchPoint(int x, int y) { - View point = new View(context); - point.setBackgroundResource(R.drawable.un_touch_point); - WindowManager.LayoutParams params = createTouchPointLayoutParams(x, y); - windowManager.addView(point, params); - moreTouchPointViews.add(point); - moreTouchPointParams.add(params); - - point.setOnTouchListener(new View.OnTouchListener() { - private float lastX, lastY, startX, startY; - - @Override - public boolean onTouch(View v, MotionEvent event) { - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: - lastX = event.getRawX(); - lastY = event.getRawY(); - startX = params.x; - startY = params.y; - break; - case MotionEvent.ACTION_MOVE: - float dx = event.getRawX() - lastX; - float dy = event.getRawY() - lastY; - params.x = (int) (startX + dx); - params.y = (int) (startY + dy); - windowManager.updateViewLayout(v, params); - logDebug("多点触摸点移动到: (" + params.x + ", " + params.y + ")"); - break; - } - return true; - } - }); - } - - private void removeLastTouchPoint() { - if (moreTouchPointViews.size() <= 1) { - Toast.makeText(context, "至少保留一个触摸点", Toast.LENGTH_SHORT).show(); - return; - } - int lastIndex = moreTouchPointViews.size() - 1; - View last = moreTouchPointViews.remove(lastIndex); - moreTouchPointParams.remove(lastIndex); - windowManager.removeView(last); - } - - private WindowManager.LayoutParams createTouchPointLayoutParams(int x, int y) { - WindowManager.LayoutParams params = new WindowManager.LayoutParams( - 100, 100, - Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? - WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY : - WindowManager.LayoutParams.TYPE_PHONE, - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | - WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, - PixelFormat.TRANSLUCENT - ); - params.gravity = Gravity.TOP | Gravity.START; - params.x = x; - params.y = y; - return params; - } - private void updateTouchPointPosition(float paramX, float paramY, float dx, float dy) { Point constrainedPoint = ViewUtils.constrainToScreen( paramX + dx, paramY + dy, screenWidth - singleTouchPointView.getWidth(), screenHeight - singleTouchPointView.getHeight()); @@ -520,6 +531,14 @@ public class FloatingViewManager { windowManager.updateViewLayout(moreControlBarView, moreControlBarParams); } + private List getMoreTouchPositions() { + List points = new ArrayList<>(); + for (WindowManager.LayoutParams params : moreTouchPointParams) { + points.add(new Point(params.x, params.y)); + } + return points; + } + public void showInputDialog() { EditText input = new EditText(context); input.setInputType(InputType.TYPE_CLASS_NUMBER); @@ -569,30 +588,37 @@ public class FloatingViewManager { }); } - public void flashTouchPoint() { - if (singleTouchPointView != null) { - singleTouchPointView.animate() - .alpha(0.3f) - .setDuration(100) - .withEndAction(() -> - singleTouchPointView.animate() - .alpha(1.0f) - .setDuration(100) - .start() - ) - .start(); - } - for (View point : moreTouchPointViews) { - point.animate() - .alpha(0.3f) - .setDuration(100) - .withEndAction(() -> - point.animate() - .alpha(1.0f) - .setDuration(100) - .start() - ) - .start(); + // 改成只闪烁当前索引的触摸点 + public void flashTouchPoint(int index) { + if (index == -1) { + // 单点模式 + if (singleTouchPointView != null) { + singleTouchPointView.animate() + .alpha(0.3f) + .setDuration(100) + .withEndAction(() -> + singleTouchPointView.animate() + .alpha(1.0f) + .setDuration(100) + .start() + ) + .start(); + } + } else { + // 多点模式 + if (index >= 0 && index < moreTouchPointViews.size()) { + View point = moreTouchPointViews.get(index); + point.animate() + .alpha(0.3f) + .setDuration(100) + .withEndAction(() -> + point.animate() + .alpha(1.0f) + .setDuration(100) + .start() + ) + .start(); + } } } diff --git a/app/src/main/res/drawable/add.xml b/app/src/main/res/drawable/add.xml new file mode 100644 index 0000000..6c8ce27 --- /dev/null +++ b/app/src/main/res/drawable/add.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/remove.xml b/app/src/main/res/drawable/remove.xml new file mode 100644 index 0000000..426b973 --- /dev/null +++ b/app/src/main/res/drawable/remove.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/slide.xml b/app/src/main/res/drawable/slide.xml new file mode 100644 index 0000000..e9fc487 --- /dev/null +++ b/app/src/main/res/drawable/slide.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/app/src/main/res/layout/more_control_bar.xml b/app/src/main/res/layout/more_control_bar.xml index 53ac0dc..3bee0e0 100644 --- a/app/src/main/res/layout/more_control_bar.xml +++ b/app/src/main/res/layout/more_control_bar.xml @@ -20,14 +20,21 @@ android:layout_width="48dp" android:layout_height="48dp" android:layout_marginBottom="8dp" - android:src="@drawable/save" /> + android:src="@drawable/add" /> + android:src="@drawable/remove" /> + +