This commit is contained in:
lihongwei 2025-06-18 14:29:45 +08:00
parent 5ac7eb909d
commit 0b20d1a01a
5 changed files with 138 additions and 37 deletions

View File

@ -21,6 +21,7 @@ import androidx.activity.EdgeToEdge;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
@ -140,18 +141,25 @@ public class MainActivity extends AppCompatActivity {
binding.animatedView.setOnClickListener(v -> onToggleFloatingWindowClicked());
binding.single.setOnClickListener(v -> {
if (isFloatingShown != FLOATING_NONE) {
Toast.makeText(this, "请先关闭悬浮窗再切换模式", Toast.LENGTH_SHORT).show();
return;
}
selectedFloatingMode = FLOATING_SINGLE;
updateSelectionButtons();
logDebug("选择单点模式. selectedFloatingMode=" + selectedFloatingMode);
});
binding.multi.setOnClickListener(v -> {
if (isFloatingShown != FLOATING_NONE) {
Toast.makeText(this, "请先关闭悬浮窗再切换模式", Toast.LENGTH_SHORT).show();
return;
}
selectedFloatingMode = FLOATING_MULTI;
updateSelectionButtons();
logDebug("选择多点模式. selectedFloatingMode=" + selectedFloatingMode);
});
}
private void checkPermissions() {
@ -205,7 +213,6 @@ public class MainActivity extends AppCompatActivity {
}
}
private void showPermissionRequest(Intent intent, String toastMessage, String errorMessage) {
try {
permissionLauncher.launch(intent);
@ -270,7 +277,6 @@ public class MainActivity extends AppCompatActivity {
return FLOATING_NONE;
}
public void onToggleFloatingWindowClicked() {
long currentTime = System.currentTimeMillis();
if (currentTime - lastClickTime < DEBOUNCE_INTERVAL) {
@ -341,13 +347,23 @@ public class MainActivity extends AppCompatActivity {
private void updateSelectionButtons() {
logDebug("更新选择按钮UI: selectedFloatingMode=" + selectedFloatingMode);
if (selectedFloatingMode == FLOATING_SINGLE) {
binding.single.setSelected(true);
binding.multi.setSelected(false);
binding.single.setBackgroundTintList(ContextCompat.getColorStateList(this, R.color.button_selected));
binding.multi.setBackgroundTintList(ContextCompat.getColorStateList(this, R.color.button_unselected));
} else if (selectedFloatingMode == FLOATING_MULTI) {
binding.single.setSelected(false);
binding.multi.setSelected(true);
binding.single.setBackgroundTintList(ContextCompat.getColorStateList(this, R.color.button_unselected));
binding.multi.setBackgroundTintList(ContextCompat.getColorStateList(this, R.color.button_selected));
}
binding.single.setEnabled(isFloatingShown == FLOATING_NONE);
binding.multi.setEnabled(isFloatingShown == FLOATING_NONE);
}
private void setStartButtonEnabled(boolean enabled) {
@ -363,7 +379,6 @@ public class MainActivity extends AppCompatActivity {
binding.animatedVideo.start();
}
@Override
protected void onDestroy() {
super.onDestroy();

View File

@ -77,14 +77,15 @@ public class FloatingViewManager {
throw new SecurityException("需要悬浮窗许可");
}
removeFloatingViews();
showMultipleModeViews(mode);
removeFloatingViews(); // 移除已有悬浮窗
showMultipleModeViews(mode); // 显示新模式悬浮窗
Log.d(TAG, "添加悬浮窗, 模式 = " + mode);
}
public void removeFloatingViews() {
try {
// 移除点事件视图
for (EventWrapper wrapper : new ArrayList<>(runtimeEvents)) {
if (wrapper.getType() == EventWrapper.EventType.POINT) {
PointEvent pe = (PointEvent) wrapper.getEvent();
@ -92,6 +93,7 @@ public class FloatingViewManager {
}
}
// 移除滑动事件视图
for (EventWrapper wrapper : new ArrayList<>(runtimeEvents)) {
if (wrapper.getType() == EventWrapper.EventType.SLIDE) {
SlideEvent se = (SlideEvent) wrapper.getEvent();
@ -103,8 +105,6 @@ public class FloatingViewManager {
runtimeEvents.clear();
Log.d(TAG, "remove runtimeEvents: " + runtimeEvents.size() + " eventOrderCounter :" + eventOrderCounter);
if (multipleControlBarView != null) {
safeRemoveView(multipleControlBarView);
multipleControlBarView = null;
@ -127,6 +127,7 @@ public class FloatingViewManager {
}
private void closeFloatingViews() {
// 停止自动点击服务
AutoClickService service = AutoClickService.getInstance();
if (service != null) {
service.stopClicking();
@ -135,31 +136,30 @@ public class FloatingViewManager {
Toast.makeText(context, "请同意无障碍服务权限", Toast.LENGTH_SHORT).show();
}
updateTouchPointsBackground(R.drawable.un_touch_point);
removeFloatingViews();
updateTouchPointsBackground(R.drawable.ring_has_bg);
removeFloatingViews(); // 移除所有悬浮窗
context.stopService(new Intent(context, ForegroundService.class));
PrefUtils.setFloatingShown(context, 0);
// 发送浮窗关闭广播
Intent intent = new Intent("com.auto.autoclicker.FLOATING_WINDOW_STATE_CHANGED");
intent.putExtra("isShown", false);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
}
private void showMultipleModeViews(int mode) {
initMultipleTouchPointView();
initMultipleControlBar();
initMultipleTouchPointView(); // 初始化点击点数据
initMultipleControlBar(); // 初始化控制栏视图
if (multipleControlBarView != null) {
windowManager.addView(multipleControlBarView, multipleControlBarParams);
windowManager.addView(multipleControlBarView, multipleControlBarParams); // 显示控制栏
}
}
private void initMultipleTouchPointView() {
runtimeEvents.clear();
eventOrderCounter = 1;
Log.d(TAG, "init runtimeEvents: " + runtimeEvents.size() + " eventOrderCounter :" + eventOrderCounter);
}
@SuppressLint("ClickableViewAccessibility")
@ -167,9 +167,9 @@ public class FloatingViewManager {
multipleControlBarView = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.multiple_control_bar, null);
multipleControlBarParams = createControlBarParams();
setupDraggableView(multipleControlBarView, multipleControlBarParams, this::updateMoreControlBarPosition);
setupDraggableView(multipleControlBarView, multipleControlBarParams, this::updateMoreControlBarPosition); // 可拖动
setupControlButtons(multipleControlBarView);
setupControlButtons(multipleControlBarView); // 初始化按钮功能
}
private void setupControlButtons(LinearLayout controlBar) {
@ -180,6 +180,7 @@ public class FloatingViewManager {
ImageView closeButton = controlBar.findViewById(R.id.close_button);
ImageView settingButton = controlBar.findViewById(R.id.settings_button);
// 按钮点击事件绑定
playButton.setOnClickListener(v -> toggleMultipleClicking());
addButton.setOnClickListener(v -> addPointEvent());
removeButton.setOnClickListener(v -> removeLastEvent());
@ -188,17 +189,8 @@ public class FloatingViewManager {
settingButton.setOnClickListener(v -> showInputDialog());
}
private TextView createTouchPointView(String label) {
TextView touchPointView = new TextView(context);
touchPointView.setBackgroundResource(R.drawable.un_touch_point);
touchPointView.setGravity(Gravity.CENTER);
touchPointView.setText(label);
touchPointView.setTextColor(Color.BLACK);
touchPointView.setTextSize(16);
return touchPointView;
}
private WindowManager.LayoutParams createTouchPointParams() {
// 创建点击点的布局参数
int overlayType = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ?
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY :
WindowManager.LayoutParams.TYPE_PHONE;
@ -215,6 +207,7 @@ public class FloatingViewManager {
}
private WindowManager.LayoutParams createControlBarParams() {
// 创建控制栏的悬浮窗参数
int overlayType = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ?
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY :
WindowManager.LayoutParams.TYPE_PHONE;
@ -234,6 +227,7 @@ public class FloatingViewManager {
}
private WindowManager.LayoutParams createLineViewParams() {
// 创建连接线滑动路径的参数全屏不可点击
int overlayType = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ?
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY :
WindowManager.LayoutParams.TYPE_PHONE;
@ -260,19 +254,22 @@ public class FloatingViewManager {
return;
}
// 创建点击点视图
TextView point = createTouchPointView(String.valueOf(eventOrderCounter));
// 设置位置居中
WindowManager.LayoutParams params = createTouchPointParams();
params.x = screenWidth / 2 - TOUCH_POINT_SIZE / 2;
params.y = screenHeight / 2 - TOUCH_POINT_SIZE / 2;
// 包装为事件对象
PointEvent pointEvent = new PointEvent(eventOrderCounter, params.x, params.y, point, params);
runtimeEvents.add(new EventWrapper(EventWrapper.EventType.POINT, pointEvent, eventOrderCounter));
eventOrderCounter++;
Log.d(TAG, "addPoint runtimeEvents: " + runtimeEvents.size() + " eventOrderCounter :" + eventOrderCounter);
// 设置拖动功能并添加到窗口
setupDraggablePoint(point, params, pointEvent);
windowManager.addView(point, params);
updateServicePositions();
@ -285,36 +282,40 @@ public class FloatingViewManager {
return;
}
// 创建起点
TextView startPoint = createTouchPointView(String.valueOf(eventOrderCounter));
WindowManager.LayoutParams startParams = createTouchPointParams();
startParams.x = screenWidth / 2 - 100;
startParams.y = screenHeight / 2 - 50;
PointEvent startPointEvent = new PointEvent(eventOrderCounter, startParams.x, startParams.y, startPoint, startParams);
// 创建终点
TextView endPoint = createTouchPointView(String.valueOf(eventOrderCounter));
WindowManager.LayoutParams endParams = createTouchPointParams();
endParams.x = screenWidth / 2 + 100;
endParams.y = screenHeight / 2 - 50;
PointEvent endPointEvent = new PointEvent(eventOrderCounter, endParams.x, endParams.y, endPoint, endParams);
// 创建滑动连线
ConnectingLineView lineView = new ConnectingLineView(context);
WindowManager.LayoutParams lineParams = createLineViewParams();
SlideEvent slideEvent = new SlideEvent(eventOrderCounter, startPointEvent, endPointEvent, lineView, lineParams);
runtimeEvents.add(new EventWrapper(EventWrapper.EventType.SLIDE, slideEvent, eventOrderCounter));
eventOrderCounter++;
Log.d(TAG, "addSlide runtimeEvents: " + runtimeEvents.size() + " eventOrderCounter :" + eventOrderCounter);
// 设置滑动点可拖动
setupDraggableSlidePoint(startPoint, startParams, startPointEvent, slideEvent);
setupDraggableSlidePoint(endPoint, endParams, endPointEvent, slideEvent);
// 添加视图到窗口
windowManager.addView(lineView, lineParams);
windowManager.addView(startPoint, startParams);
windowManager.addView(endPoint, endParams);
updateLinePosition(slideEvent);
updateLinePosition(slideEvent); // 更新线的位置
updateServicePositions();
}
@ -329,6 +330,7 @@ public class FloatingViewManager {
return;
}
// 移除最后一个事件
Event lastEvent = runtimeEvents.remove(runtimeEvents.size() - 1).getEvent();
removeEvent(lastEvent);
eventOrderCounter--;
@ -337,6 +339,7 @@ public class FloatingViewManager {
private void removeEvent(Event event) {
try {
// 判断类型并移除相关视图
if (event instanceof PointEvent) {
PointEvent pointEvent = (PointEvent) event;
windowManager.removeView(pointEvent.getView());
@ -352,6 +355,7 @@ public class FloatingViewManager {
}
private void updateServicePositions() {
// 更新服务中记录的位置
AutoClickService service = AutoClickService.getInstance();
if (service != null) {
service.addMultipleClickEvents(runtimeEvents);
@ -363,7 +367,7 @@ public class FloatingViewManager {
AutoClickService service = AutoClickService.getInstance();
if (service == null) {
handleMissingService();
handleMissingService(); // 无障碍服务未开启
return;
}
@ -373,9 +377,9 @@ public class FloatingViewManager {
}
if (isMultipleRunning) {
stopMultiClicking(service);
stopMultiClicking(service); // 停止点击
} else {
startMultiClicking(service);
startMultiClicking(service); // 开始点击
}
isMultipleRunning = !isMultipleRunning;
@ -396,7 +400,7 @@ public class FloatingViewManager {
service.stopClicking();
Toast.makeText(context, "多点点击停止", Toast.LENGTH_SHORT).show();
updateTouchPointsBackground(R.drawable.un_touch_point);
updateTouchPointsBackground(R.drawable.ring_has_bg);
}
private void updateTouchPointsBackground(int resourceId) {
@ -594,6 +598,17 @@ public class FloatingViewManager {
lineView.setPoints(startCenterX, startCenterY, endCenterX, endCenterY);
}
private TextView createTouchPointView(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.setTextSize(19);
return touchPointView;
}
public void showInputDialog() {
EditText input = new EditText(context);
input.setInputType(InputType.TYPE_CLASS_NUMBER);

View File

@ -61,8 +61,8 @@
<View
android:id="@+id/animated_view"
android:layout_width="350dp"
android:layout_height="350dp"
android:layout_width="250dp"
android:layout_height="250dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"

View File

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="38dp"
android:layout_height="wrap_content"
android:background="@drawable/control_bar_bg"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="vertical"
android:paddingHorizontal="10dp">
<ImageView
android:id="@+id/play_button"
android:layout_width="13dp"
android:layout_height="13dp"
android:layout_marginTop="15dp"
android:layout_marginBottom="16dp"
android:src="@drawable/play" />
<ImageView
android:id="@+id/save_button"
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_marginBottom="16dp"
android:src="@drawable/save" />
<ImageView
android:id="@+id/eye_button"
android:layout_width="16dp"
android:layout_height="9dp"
android:layout_marginBottom="16dp"
android:src="@drawable/eye" />
<ImageView
android:id="@+id/settings_button"
android:layout_width="14dp"
android:layout_height="14dp"
android:layout_marginBottom="9dp"
android:src="@drawable/control_setting" />
</LinearLayout>
<ImageView
android:id="@+id/cut_off"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginBottom="10dp"
android:scaleType="fitXY"
android:src="@drawable/cut_off_line" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="vertical"
android:paddingHorizontal="10dp">
<ImageView
android:id="@+id/close_button"
android:layout_width="10dp"
android:layout_height="10dp"
android:layout_marginBottom="11dp"
android:src="@drawable/cancel" />
</LinearLayout>
</LinearLayout>

View File

@ -1,10 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="black">#FF000000</color>
<color name="activity_black">#171717</color>
<color name="white">#FFFFFFFF</color>
<color name="blue">#0BC4FC</color>
<color name="gray">#616161</color>
<color name="bg_blue">#113945</color>
<color name="text_gray">#8DA5A7</color>
<color name="button_gray">#446672</color>
<color name="button_selected">#1A546B</color>
<color name="button_unselected">#171717</color>
</resources>