功能优化
This commit is contained in:
parent
30688c11c2
commit
6693521d11
@ -87,7 +87,7 @@ public class ForegroundService extends Service {
|
|||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
if (floatingViewManager != null) {
|
if (floatingViewManager != null) {
|
||||||
floatingViewManager.removeFloatingViews();
|
floatingViewManager.removeAllFloatingViews();
|
||||||
isFloatingViewShown = false;
|
isFloatingViewShown = false;
|
||||||
Log.d(TAG, "悬浮窗已移除");
|
Log.d(TAG, "悬浮窗已移除");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
package com.auto.clicker.autoclicker.ui.floating;
|
package com.auto.clicker.autoclicker.ui.adapter.floating;
|
||||||
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@ -16,7 +16,6 @@ public class SolutionAdapter extends RecyclerView.Adapter<SolutionAdapter.Soluti
|
|||||||
private List<Solution> solutionList;
|
private List<Solution> solutionList;
|
||||||
private OnSolutionClickListener listener;
|
private OnSolutionClickListener listener;
|
||||||
|
|
||||||
// 定义接口用于处理点击事件
|
|
||||||
public interface OnSolutionClickListener {
|
public interface OnSolutionClickListener {
|
||||||
void onSolutionClick(Solution solution);
|
void onSolutionClick(Solution solution);
|
||||||
}
|
}
|
||||||
@ -30,7 +29,7 @@ public class SolutionAdapter extends RecyclerView.Adapter<SolutionAdapter.Soluti
|
|||||||
@Override
|
@Override
|
||||||
public SolutionViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
public SolutionViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
View view = LayoutInflater.from(parent.getContext())
|
View view = LayoutInflater.from(parent.getContext())
|
||||||
.inflate(android.R.layout.simple_list_item_1, parent, false); // 可以自定义更复杂的item布局
|
.inflate(android.R.layout.simple_list_item_1, parent, false);
|
||||||
return new SolutionViewHolder(view);
|
return new SolutionViewHolder(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,7 +63,6 @@ public class SolutionAdapter extends RecyclerView.Adapter<SolutionAdapter.Soluti
|
|||||||
|
|
||||||
SolutionViewHolder(View itemView) {
|
SolutionViewHolder(View itemView) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
// simple_list_item_1 只有一个 TextView
|
|
||||||
solutionNameTextView = itemView.findViewById(android.R.id.text1);
|
solutionNameTextView = itemView.findViewById(android.R.id.text1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,61 @@
|
|||||||
|
package com.auto.clicker.autoclicker.util;
|
||||||
|
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
|
||||||
|
public class DraggableHelper {
|
||||||
|
|
||||||
|
public interface DragCallback {
|
||||||
|
void onPositionChanged(int x, int y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void makeDraggable(View view,
|
||||||
|
WindowManager.LayoutParams params,
|
||||||
|
WindowManager windowManager,
|
||||||
|
int screenWidth, int screenHeight,
|
||||||
|
DragCallback callback) {
|
||||||
|
|
||||||
|
view.setOnTouchListener(new View.OnTouchListener() {
|
||||||
|
private float lastX, lastY;
|
||||||
|
private float paramX, paramY;
|
||||||
|
|
||||||
|
@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;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case MotionEvent.ACTION_MOVE:
|
||||||
|
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:
|
||||||
|
v.performClick();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,166 @@
|
|||||||
|
package com.auto.clicker.autoclicker.util;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.PixelFormat;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.Gravity;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.auto.clicker.autoclicker.R;
|
||||||
|
import com.auto.clicker.autoclicker.data.PointEvent;
|
||||||
|
import com.auto.clicker.autoclicker.data.SlideEvent;
|
||||||
|
import com.auto.clicker.autoclicker.view.ConnectingLineView;
|
||||||
|
|
||||||
|
public class EventViewBinder {
|
||||||
|
|
||||||
|
public interface OnPositionChangedCallback {
|
||||||
|
void onPositionChanged(int x, int y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void bindPoint(Context context, WindowManager windowManager,
|
||||||
|
PointEvent pointEvent, int touchPointSize,
|
||||||
|
int screenWidth, int screenHeight,
|
||||||
|
OnPositionChangedCallback callback,int order) {
|
||||||
|
|
||||||
|
TextView pointView = createTouchPointView(context, String.valueOf(order));
|
||||||
|
Log.d("bind","id: " + order);
|
||||||
|
WindowManager.LayoutParams params = createTouchPointParams(context, touchPointSize);
|
||||||
|
|
||||||
|
params.x = pointEvent.getX();
|
||||||
|
params.y = pointEvent.getY();
|
||||||
|
|
||||||
|
pointEvent.setView(pointView);
|
||||||
|
pointEvent.setLayoutParams(params);
|
||||||
|
|
||||||
|
DraggableHelper.makeDraggable(pointView, params, windowManager,
|
||||||
|
screenWidth, screenHeight,
|
||||||
|
(x, y) -> {
|
||||||
|
pointEvent.setX(x);
|
||||||
|
pointEvent.setY(y);
|
||||||
|
if (callback != null) callback.onPositionChanged(x, y);
|
||||||
|
});
|
||||||
|
|
||||||
|
windowManager.addView(pointView, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void bindSlide(Context context, WindowManager windowManager,
|
||||||
|
SlideEvent slideEvent, int touchPointSize,
|
||||||
|
int screenWidth, int screenHeight,
|
||||||
|
OnPositionChangedCallback callback,int order) {
|
||||||
|
|
||||||
|
PointEvent start = slideEvent.getStartPoint();
|
||||||
|
PointEvent end = slideEvent.getEndPoint();
|
||||||
|
|
||||||
|
TextView startView = createTouchPointView(context, String.valueOf(order));
|
||||||
|
TextView endView = createTouchPointView(context, String.valueOf(order));
|
||||||
|
WindowManager.LayoutParams startParams = createTouchPointParams(context, touchPointSize);
|
||||||
|
WindowManager.LayoutParams endParams = createTouchPointParams(context, touchPointSize);
|
||||||
|
|
||||||
|
startParams.x = start.getX();
|
||||||
|
startParams.y = start.getY();
|
||||||
|
endParams.x = end.getX();
|
||||||
|
endParams.y = end.getY();
|
||||||
|
|
||||||
|
start.setView(startView);
|
||||||
|
start.setLayoutParams(startParams);
|
||||||
|
end.setView(endView);
|
||||||
|
end.setLayoutParams(endParams);
|
||||||
|
|
||||||
|
ConnectingLineView lineView = new ConnectingLineView(context);
|
||||||
|
WindowManager.LayoutParams lineParams = createLineViewParams(context);
|
||||||
|
|
||||||
|
slideEvent.setLineView(lineView);
|
||||||
|
slideEvent.setLineParams(lineParams);
|
||||||
|
|
||||||
|
// 拖动起点
|
||||||
|
DraggableHelper.makeDraggable(startView, startParams, windowManager,
|
||||||
|
screenWidth, screenHeight,
|
||||||
|
(x, y) -> {
|
||||||
|
start.setX(x);
|
||||||
|
start.setY(y);
|
||||||
|
updateLinePosition(slideEvent, touchPointSize);
|
||||||
|
if (callback != null) callback.onPositionChanged(x, y);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 拖动终点
|
||||||
|
DraggableHelper.makeDraggable(endView, endParams, windowManager,
|
||||||
|
screenWidth, screenHeight,
|
||||||
|
(x, y) -> {
|
||||||
|
end.setX(x);
|
||||||
|
end.setY(y);
|
||||||
|
updateLinePosition(slideEvent, touchPointSize);
|
||||||
|
if (callback != null) callback.onPositionChanged(x, y);
|
||||||
|
});
|
||||||
|
|
||||||
|
windowManager.addView(lineView, lineParams);
|
||||||
|
windowManager.addView(startView, startParams);
|
||||||
|
windowManager.addView(endView, endParams);
|
||||||
|
|
||||||
|
updateLinePosition(slideEvent, touchPointSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
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.setTextSize(19);
|
||||||
|
return touchPointView;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static WindowManager.LayoutParams createTouchPointParams(Context context, int size) {
|
||||||
|
int overlayType = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ?
|
||||||
|
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY :
|
||||||
|
WindowManager.LayoutParams.TYPE_PHONE;
|
||||||
|
|
||||||
|
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
|
||||||
|
size, size,
|
||||||
|
overlayType,
|
||||||
|
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
|
||||||
|
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
|
||||||
|
PixelFormat.TRANSLUCENT
|
||||||
|
);
|
||||||
|
params.gravity = Gravity.TOP | Gravity.START;
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static WindowManager.LayoutParams createLineViewParams(Context context) {
|
||||||
|
int overlayType = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ?
|
||||||
|
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY :
|
||||||
|
WindowManager.LayoutParams.TYPE_PHONE;
|
||||||
|
|
||||||
|
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
|
||||||
|
WindowManager.LayoutParams.MATCH_PARENT,
|
||||||
|
WindowManager.LayoutParams.MATCH_PARENT,
|
||||||
|
overlayType,
|
||||||
|
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
|
||||||
|
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
|
||||||
|
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
|
||||||
|
PixelFormat.TRANSLUCENT
|
||||||
|
);
|
||||||
|
params.gravity = Gravity.TOP | Gravity.START;
|
||||||
|
params.x = 0;
|
||||||
|
params.y = 0;
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void updateLinePosition(SlideEvent slideEvent, int touchPointSize) {
|
||||||
|
PointEvent start = slideEvent.getStartPoint();
|
||||||
|
PointEvent end = slideEvent.getEndPoint();
|
||||||
|
ConnectingLineView lineView = slideEvent.getLineView();
|
||||||
|
|
||||||
|
if (lineView == null) return;
|
||||||
|
|
||||||
|
float startCenterX = start.getX() + (float) touchPointSize / 2;
|
||||||
|
float startCenterY = start.getY() + (float) touchPointSize / 2;
|
||||||
|
float endCenterX = end.getX() + (float) touchPointSize / 2;
|
||||||
|
float endCenterY = end.getY() + (float) touchPointSize / 2;
|
||||||
|
|
||||||
|
lineView.setPoints(startCenterX, startCenterY, endCenterX, endCenterY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package com.auto.clicker.autoclicker.util;
|
package com.auto.clicker.autoclicker.view;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.PixelFormat;
|
import android.graphics.PixelFormat;
|
||||||
@ -23,8 +23,7 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||||||
import com.auto.clicker.autoclicker.R;
|
import com.auto.clicker.autoclicker.R;
|
||||||
import com.auto.clicker.autoclicker.room.entity.Solution;
|
import com.auto.clicker.autoclicker.room.entity.Solution;
|
||||||
import com.auto.clicker.autoclicker.room.repository.EventRepository;
|
import com.auto.clicker.autoclicker.room.repository.EventRepository;
|
||||||
import com.auto.clicker.autoclicker.ui.floating.SolutionAdapter;
|
import com.auto.clicker.autoclicker.ui.adapter.floating.SolutionAdapter;
|
||||||
import com.auto.clicker.autoclicker.view.FloatingViewManager;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -69,7 +68,7 @@ public class FloatingTabDialogManager {
|
|||||||
Context themedContext = new ContextThemeWrapper(context, R.style.Theme_AutoClicker);
|
Context themedContext = new ContextThemeWrapper(context, R.style.Theme_AutoClicker);
|
||||||
|
|
||||||
floatingDialogView = (LinearLayout) LayoutInflater.from(themedContext).inflate(R.layout.floating_tab_dialog, null);
|
floatingDialogView = (LinearLayout) LayoutInflater.from(themedContext).inflate(R.layout.floating_tab_dialog, null);
|
||||||
floatingDialogParams = createFloatingDialogParams(); // 创建悬浮窗参数
|
floatingDialogParams = createFloatingDialogParams();
|
||||||
|
|
||||||
saveTab = floatingDialogView.findViewById(R.id.tab_one_button);
|
saveTab = floatingDialogView.findViewById(R.id.tab_one_button);
|
||||||
loadTab = floatingDialogView.findViewById(R.id.tab_two_button);
|
loadTab = floatingDialogView.findViewById(R.id.tab_two_button);
|
||||||
@ -105,7 +104,6 @@ public class FloatingTabDialogManager {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 这个可能也是在后台线程,保险起见也用主线程
|
|
||||||
showToastOnUi(context, "正在保存方案...");
|
showToastOnUi(context, "正在保存方案...");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,9 +126,9 @@ public class FloatingTabDialogManager {
|
|||||||
});
|
});
|
||||||
loadRecyclerview.setAdapter(solutionsAdapter);
|
loadRecyclerview.setAdapter(solutionsAdapter);
|
||||||
|
|
||||||
showPage(0); // 默认显示保存页面
|
showPage(0);
|
||||||
|
|
||||||
loadSolutionsForList(); // 加载方案列表,以便切换到加载页面时可以直接显示
|
loadSolutionsForList();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
windowManager.addView(floatingDialogView, floatingDialogParams);
|
windowManager.addView(floatingDialogView, floatingDialogParams);
|
||||||
@ -150,22 +148,18 @@ public class FloatingTabDialogManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 隐藏所有页面
|
|
||||||
savePage.setVisibility(View.GONE);
|
savePage.setVisibility(View.GONE);
|
||||||
loadPage.setVisibility(View.GONE);
|
loadPage.setVisibility(View.GONE);
|
||||||
|
|
||||||
// 重置Tab按钮颜色
|
|
||||||
saveTab.setTextColor(context.getResources().getColor(android.R.color.darker_gray));
|
saveTab.setTextColor(context.getResources().getColor(android.R.color.darker_gray));
|
||||||
loadTab.setTextColor(context.getResources().getColor(android.R.color.darker_gray));
|
loadTab.setTextColor(context.getResources().getColor(android.R.color.darker_gray));
|
||||||
|
|
||||||
switch (pageIndex) {
|
switch (pageIndex) {
|
||||||
case 0: // 保存页面
|
case 0:
|
||||||
savePage.setVisibility(View.VISIBLE);
|
savePage.setVisibility(View.VISIBLE);
|
||||||
saveTab.setTextColor(context.getResources().getColor(android.R.color.black));
|
saveTab.setTextColor(context.getResources().getColor(android.R.color.black));
|
||||||
// 在显示保存页面时尝试显示键盘
|
|
||||||
showKeyboard();
|
|
||||||
break;
|
break;
|
||||||
case 1: // 加载页面
|
case 1:
|
||||||
loadPage.setVisibility(View.VISIBLE);
|
loadPage.setVisibility(View.VISIBLE);
|
||||||
loadTab.setTextColor(context.getResources().getColor(android.R.color.black));
|
loadTab.setTextColor(context.getResources().getColor(android.R.color.black));
|
||||||
loadSolutionsForList();
|
loadSolutionsForList();
|
||||||
@ -176,7 +170,6 @@ public class FloatingTabDialogManager {
|
|||||||
private void loadSolutionsForList() {
|
private void loadSolutionsForList() {
|
||||||
if (floatingViewManager == null) {
|
if (floatingViewManager == null) {
|
||||||
Log.e(TAG, "FloatingViewManager 未设置,无法加载方案列表。");
|
Log.e(TAG, "FloatingViewManager 未设置,无法加载方案列表。");
|
||||||
// 确保UI操作在主线程
|
|
||||||
new Handler(Looper.getMainLooper()).post(() ->
|
new Handler(Looper.getMainLooper()).post(() ->
|
||||||
Toast.makeText(context, "加载方案列表功能不可用。", Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, "加载方案列表功能不可用。", Toast.LENGTH_SHORT).show()
|
||||||
);
|
);
|
||||||
@ -185,7 +178,6 @@ public class FloatingTabDialogManager {
|
|||||||
floatingViewManager.getAllSolutions(new EventRepository.RepositoryCallback<List<Solution>>() {
|
floatingViewManager.getAllSolutions(new EventRepository.RepositoryCallback<List<Solution>>() {
|
||||||
@Override
|
@Override
|
||||||
public void onComplete(List<Solution> solutions) {
|
public void onComplete(List<Solution> solutions) {
|
||||||
// 将 UI 更新操作(包括更新适配器和显示Toast)切换到主线程
|
|
||||||
new Handler(Looper.getMainLooper()).post(() -> {
|
new Handler(Looper.getMainLooper()).post(() -> {
|
||||||
solutionsAdapter.setSolutions(solutions);
|
solutionsAdapter.setSolutions(solutions);
|
||||||
if (solutions.isEmpty()) {
|
if (solutions.isEmpty()) {
|
||||||
@ -196,7 +188,6 @@ public class FloatingTabDialogManager {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onError(Exception e) {
|
public void onError(Exception e) {
|
||||||
// 将 UI 更新操作(显示Toast)切换到主线程
|
|
||||||
new Handler(Looper.getMainLooper()).post(() -> {
|
new Handler(Looper.getMainLooper()).post(() -> {
|
||||||
Log.e(TAG, "加载方案列表失败: " + e.getMessage(), e);
|
Log.e(TAG, "加载方案列表失败: " + e.getMessage(), e);
|
||||||
Toast.makeText(context, "加载方案列表失败。", Toast.LENGTH_SHORT).show();
|
Toast.makeText(context, "加载方案列表失败。", Toast.LENGTH_SHORT).show();
|
||||||
@ -209,7 +200,7 @@ public class FloatingTabDialogManager {
|
|||||||
if (floatingDialogView != null) {
|
if (floatingDialogView != null) {
|
||||||
try {
|
try {
|
||||||
windowManager.removeView(floatingDialogView);
|
windowManager.removeView(floatingDialogView);
|
||||||
floatingDialogView = null; // 置空,防止重复移除或空指针异常
|
floatingDialogView = null;
|
||||||
Log.d(TAG, "浮动标签页弹窗已移除");
|
Log.d(TAG, "浮动标签页弹窗已移除");
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
Log.w(TAG, "尝试移除不存在的视图", e);
|
Log.w(TAG, "尝试移除不存在的视图", e);
|
||||||
@ -234,17 +225,6 @@ public class FloatingTabDialogManager {
|
|||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showKeyboard() {
|
|
||||||
if (inputName != null) {
|
|
||||||
inputName.requestFocus(); // 确保输入框获取焦点
|
|
||||||
InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
|
|
||||||
if (imm != null) {
|
|
||||||
// 尝试强制显示键盘
|
|
||||||
imm.showSoftInput(inputName, InputMethodManager.SHOW_IMPLICIT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void showToastOnUi(Context context, String msg) {
|
public static void showToastOnUi(Context context, String msg) {
|
||||||
new Handler(Looper.getMainLooper()).post(() ->
|
new Handler(Looper.getMainLooper()).post(() ->
|
||||||
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show()
|
||||||
@ -1,15 +1,12 @@
|
|||||||
package com.auto.clicker.autoclicker.view;
|
package com.auto.clicker.autoclicker.view;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.graphics.Color;
|
|
||||||
import android.graphics.PixelFormat;
|
import android.graphics.PixelFormat;
|
||||||
import android.graphics.Point;
|
import android.graphics.Point;
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
@ -25,7 +22,6 @@ import android.view.inputmethod.InputMethodManager;
|
|||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
@ -45,7 +41,7 @@ import com.auto.clicker.autoclicker.room.entity.TouchPoint;
|
|||||||
import com.auto.clicker.autoclicker.room.repository.EventRepository;
|
import com.auto.clicker.autoclicker.room.repository.EventRepository;
|
||||||
import com.auto.clicker.autoclicker.service.AutoClickService;
|
import com.auto.clicker.autoclicker.service.AutoClickService;
|
||||||
import com.auto.clicker.autoclicker.service.ForegroundService;
|
import com.auto.clicker.autoclicker.service.ForegroundService;
|
||||||
import com.auto.clicker.autoclicker.util.FloatingTabDialogManager;
|
import com.auto.clicker.autoclicker.util.EventViewBinder;
|
||||||
import com.auto.clicker.autoclicker.util.PrefUtils;
|
import com.auto.clicker.autoclicker.util.PrefUtils;
|
||||||
import com.auto.clicker.autoclicker.util.ScreenUtils;
|
import com.auto.clicker.autoclicker.util.ScreenUtils;
|
||||||
import com.auto.clicker.autoclicker.util.ViewUtils;
|
import com.auto.clicker.autoclicker.util.ViewUtils;
|
||||||
@ -74,9 +70,9 @@ public class FloatingViewManager {
|
|||||||
|
|
||||||
private boolean areEventsVisible = true;
|
private boolean areEventsVisible = true;
|
||||||
|
|
||||||
private FloatingTabDialogManager floatingTabDialogManager;
|
private final FloatingTabDialogManager floatingTabDialogManager;
|
||||||
|
|
||||||
private EventRepository eventRepository;
|
private final EventRepository eventRepository;
|
||||||
|
|
||||||
public FloatingViewManager(Context context) {
|
public FloatingViewManager(Context context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
@ -95,7 +91,7 @@ public class FloatingViewManager {
|
|||||||
throw new SecurityException("需要悬浮窗许可");
|
throw new SecurityException("需要悬浮窗许可");
|
||||||
}
|
}
|
||||||
|
|
||||||
removeFloatingViews();
|
removeAllFloatingViews();
|
||||||
showMultipleModeViews(mode);
|
showMultipleModeViews(mode);
|
||||||
|
|
||||||
Log.d(TAG, "添加悬浮窗, 模式 = " + mode);
|
Log.d(TAG, "添加悬浮窗, 模式 = " + mode);
|
||||||
@ -115,7 +111,6 @@ public class FloatingViewManager {
|
|||||||
eventOrderCounter = 1;
|
eventOrderCounter = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
|
||||||
private void initMultipleControlBar() {
|
private void initMultipleControlBar() {
|
||||||
multipleControlBarView = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.multiple_control_bar, null);
|
multipleControlBarView = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.multiple_control_bar, null);
|
||||||
multipleControlBarParams = createControlBarParams();
|
multipleControlBarParams = createControlBarParams();
|
||||||
@ -145,7 +140,6 @@ public class FloatingViewManager {
|
|||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
|
||||||
private void setupDraggableView(View view, WindowManager.LayoutParams params, PositionUpdater positionUpdater) {
|
private void setupDraggableView(View view, WindowManager.LayoutParams params, PositionUpdater positionUpdater) {
|
||||||
view.setOnTouchListener(new View.OnTouchListener() {
|
view.setOnTouchListener(new View.OnTouchListener() {
|
||||||
private float lastX, lastY;
|
private float lastX, lastY;
|
||||||
@ -216,18 +210,7 @@ public class FloatingViewManager {
|
|||||||
slideButton.setOnClickListener(v -> addSlideEvent());
|
slideButton.setOnClickListener(v -> addSlideEvent());
|
||||||
|
|
||||||
saveButton.setOnClickListener(v -> {
|
saveButton.setOnClickListener(v -> {
|
||||||
// 直接调用 FloatingTabDialogManager 来显示悬浮弹窗
|
|
||||||
// 记得要检查悬浮窗权限!
|
|
||||||
if (!Settings.canDrawOverlays(context)) {
|
|
||||||
Toast.makeText(context, "需要悬浮窗权限才能显示弹窗", Toast.LENGTH_LONG).show();
|
|
||||||
// 引导用户去开启权限
|
|
||||||
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
|
|
||||||
Uri.parse("package:" + context.getPackageName()));
|
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
||||||
context.startActivity(intent);
|
|
||||||
} else {
|
|
||||||
floatingTabDialogManager.showFloatingTabDialog();
|
floatingTabDialogManager.showFloatingTabDialog();
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
eyeButton.setOnClickListener(v -> {
|
eyeButton.setOnClickListener(v -> {
|
||||||
@ -239,6 +222,7 @@ public class FloatingViewManager {
|
|||||||
eyeButton.setImageResource(R.drawable.hide_eye);
|
eyeButton.setImageResource(R.drawable.hide_eye);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
settingButton.setOnClickListener(v -> showInputDialog());
|
settingButton.setOnClickListener(v -> showInputDialog());
|
||||||
closeButton.setOnClickListener(v -> closeFloatingViews());
|
closeButton.setOnClickListener(v -> closeFloatingViews());
|
||||||
}
|
}
|
||||||
@ -248,7 +232,7 @@ public class FloatingViewManager {
|
|||||||
|
|
||||||
AutoClickService service = AutoClickService.getInstance();
|
AutoClickService service = AutoClickService.getInstance();
|
||||||
if (service == null) {
|
if (service == null) {
|
||||||
handleMissingService(); // 无障碍服务未开启
|
handleMissingService();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,95 +242,48 @@ public class FloatingViewManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isMultipleRunning) {
|
if (isMultipleRunning) {
|
||||||
stopMultiClicking(service); // 停止点击
|
stopMultiClicking(service);
|
||||||
} else {
|
} else {
|
||||||
startMultiClicking(service); // 开始点击
|
startMultiClicking(service);
|
||||||
}
|
}
|
||||||
|
|
||||||
isMultipleRunning = !isMultipleRunning;
|
isMultipleRunning = !isMultipleRunning;
|
||||||
Log.d(TAG, "多点点击服务状态: " + service.isClicking());
|
Log.d(TAG, "多点点击服务状态: " + service.isClicking());
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
|
||||||
private void addPointEvent() {
|
private void addPointEvent() {
|
||||||
if (isMultipleRunning) {
|
if (isMultipleRunning) {
|
||||||
Toast.makeText(context, "请停止点击", Toast.LENGTH_SHORT).show();
|
Toast.makeText(context, "请停止点击", Toast.LENGTH_SHORT).show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建点击点视图
|
PointEvent pointEvent = new PointEvent(eventOrderCounter, screenWidth / 2 - TOUCH_POINT_SIZE / 2,
|
||||||
TextView pointView = createTouchPointView(String.valueOf(eventOrderCounter));
|
screenHeight / 2 - TOUCH_POINT_SIZE / 2);
|
||||||
|
|
||||||
// 设置位置居中
|
EventViewBinder.bindPoint(context, windowManager, pointEvent,
|
||||||
WindowManager.LayoutParams params = createTouchPointParams();
|
TOUCH_POINT_SIZE, screenWidth, screenHeight,
|
||||||
params.x = screenWidth / 2 - TOUCH_POINT_SIZE / 2;
|
(x, y) -> updateServicePositions(), eventOrderCounter);
|
||||||
params.y = screenHeight / 2 - TOUCH_POINT_SIZE / 2;
|
|
||||||
|
|
||||||
// 包装为事件对象
|
|
||||||
PointEvent pointEvent = new PointEvent(eventOrderCounter, params.x, params.y);
|
|
||||||
pointEvent.setView(pointView);
|
|
||||||
pointEvent.setLayoutParams(params);
|
|
||||||
|
|
||||||
runtimeEvents.add(new EventWrapper(EventWrapper.EventType.POINT, pointEvent, eventOrderCounter));
|
runtimeEvents.add(new EventWrapper(EventWrapper.EventType.POINT, pointEvent, eventOrderCounter));
|
||||||
eventOrderCounter++;
|
eventOrderCounter++;
|
||||||
|
|
||||||
Log.d(TAG, "addPoint runtimeEvents: " + runtimeEvents.size() + " eventOrderCounter :" + eventOrderCounter);
|
|
||||||
|
|
||||||
// 设置拖动功能并添加到窗口
|
|
||||||
setupDraggablePoint(pointView, params, pointEvent);
|
|
||||||
windowManager.addView(pointView, params);
|
|
||||||
updateServicePositions();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
|
||||||
private void addSlideEvent() {
|
private void addSlideEvent() {
|
||||||
if (isMultipleRunning) {
|
if (isMultipleRunning) {
|
||||||
Toast.makeText(context, "请先停止点击", Toast.LENGTH_SHORT).show();
|
Toast.makeText(context, "请先停止点击", Toast.LENGTH_SHORT).show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建起点
|
PointEvent startPoint = new PointEvent(eventOrderCounter, screenWidth / 2 - 100, screenHeight / 2 - 50);
|
||||||
TextView startPointView = createTouchPointView(String.valueOf(eventOrderCounter));
|
PointEvent endPoint = new PointEvent(eventOrderCounter, screenWidth / 2 + 100, screenHeight / 2 - 50);
|
||||||
WindowManager.LayoutParams startParams = createTouchPointParams();
|
SlideEvent slideEvent = new SlideEvent(eventOrderCounter, startPoint, endPoint);
|
||||||
startParams.x = screenWidth / 2 - 100;
|
|
||||||
startParams.y = screenHeight / 2 - 50;
|
|
||||||
PointEvent startPointEvent = new PointEvent(eventOrderCounter, startParams.x, startParams.y);
|
|
||||||
startPointEvent.setView(startPointView);
|
|
||||||
startPointEvent.setLayoutParams(startParams);
|
|
||||||
|
|
||||||
// 创建终点
|
EventViewBinder.bindSlide(context, windowManager, slideEvent,
|
||||||
TextView endPointView = createTouchPointView(String.valueOf(eventOrderCounter));
|
TOUCH_POINT_SIZE, screenWidth, screenHeight,
|
||||||
WindowManager.LayoutParams endParams = createTouchPointParams();
|
(x, y) -> updateServicePositions(), eventOrderCounter);
|
||||||
endParams.x = screenWidth / 2 + 100;
|
|
||||||
endParams.y = screenHeight / 2 - 50;
|
|
||||||
PointEvent endPointEvent = new PointEvent(eventOrderCounter, endParams.x, endParams.y);
|
|
||||||
startPointEvent.setView(endPointView);
|
|
||||||
startPointEvent.setLayoutParams(endParams);
|
|
||||||
|
|
||||||
// 创建滑动连线
|
|
||||||
ConnectingLineView lineView = new ConnectingLineView(context);
|
|
||||||
WindowManager.LayoutParams lineParams = createLineViewParams();
|
|
||||||
|
|
||||||
SlideEvent slideEvent = new SlideEvent(eventOrderCounter, startPointEvent, endPointEvent);
|
|
||||||
slideEvent.setLineView(lineView);
|
|
||||||
slideEvent.setLineParams(lineParams);
|
|
||||||
|
|
||||||
runtimeEvents.add(new EventWrapper(EventWrapper.EventType.SLIDE, slideEvent, eventOrderCounter));
|
runtimeEvents.add(new EventWrapper(EventWrapper.EventType.SLIDE, slideEvent, eventOrderCounter));
|
||||||
eventOrderCounter++;
|
eventOrderCounter++;
|
||||||
|
|
||||||
Log.d(TAG, "addSlide runtimeEvents: " + runtimeEvents.size() + " eventOrderCounter :" + eventOrderCounter);
|
|
||||||
|
|
||||||
// 设置滑动点可拖动
|
|
||||||
setupDraggableSlidePoint(startPointView, startParams, startPointEvent, slideEvent);
|
|
||||||
setupDraggableSlidePoint(endPointView, endParams, endPointEvent, slideEvent);
|
|
||||||
|
|
||||||
// 添加视图到窗口
|
|
||||||
windowManager.addView(lineView, lineParams);
|
|
||||||
windowManager.addView(startPointView, startParams);
|
|
||||||
windowManager.addView(endPointView, endParams);
|
|
||||||
|
|
||||||
updateLinePosition(slideEvent); // 更新线的位置
|
|
||||||
updateServicePositions();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void toggleEventsVisibility(boolean show) {
|
public void toggleEventsVisibility(boolean show) {
|
||||||
@ -354,7 +291,7 @@ public class FloatingViewManager {
|
|||||||
// 获取事件的视图
|
// 获取事件的视图
|
||||||
View viewToToggle = null;
|
View viewToToggle = null;
|
||||||
if (wrapper.getType() == EventWrapper.EventType.POINT) {
|
if (wrapper.getType() == EventWrapper.EventType.POINT) {
|
||||||
viewToToggle = createTouchPointView(String.valueOf(wrapper.getEvent().getId()));
|
viewToToggle = EventViewBinder.createTouchPointView(context, String.valueOf(wrapper.getEvent().getId()));
|
||||||
} else if (wrapper.getType() == EventWrapper.EventType.SLIDE) {
|
} else if (wrapper.getType() == EventWrapper.EventType.SLIDE) {
|
||||||
View startPointView = getView(show, wrapper, context);
|
View startPointView = getView(show, wrapper, context);
|
||||||
|
|
||||||
@ -388,21 +325,18 @@ public class FloatingViewManager {
|
|||||||
@NonNull
|
@NonNull
|
||||||
private View getView(boolean show, EventWrapper wrapper, Context context) {
|
private View getView(boolean show, EventWrapper wrapper, Context context) {
|
||||||
SlideEvent slideEvent = (SlideEvent) wrapper.getEvent();
|
SlideEvent slideEvent = (SlideEvent) wrapper.getEvent();
|
||||||
// 假设你只隐藏/显示点,线也需要同步
|
View startPointView = EventViewBinder.createTouchPointView(context, String.valueOf(slideEvent.getStartPoint().getId()));
|
||||||
View startPointView = createTouchPointView(String.valueOf(slideEvent.getStartPoint().getId()));
|
View endPointView = EventViewBinder.createTouchPointView(context, String.valueOf(slideEvent.getEndPoint().getId()));
|
||||||
View endPointView = createTouchPointView(String.valueOf(slideEvent.getEndPoint().getId()));
|
|
||||||
View lineView = new ConnectingLineView(context);
|
View lineView = new ConnectingLineView(context);
|
||||||
|
|
||||||
if (show) {
|
if (show) {
|
||||||
// 如果是显示,可能需要重新添加或设置可见性
|
|
||||||
// 这里假设你只是更新透明度,如果之前移除了,则需要重新addView
|
|
||||||
startPointView.setAlpha(1.0f);
|
startPointView.setAlpha(1.0f);
|
||||||
endPointView.setAlpha(1.0f);
|
endPointView.setAlpha(1.0f);
|
||||||
lineView.setAlpha(1.0f); // 如果线视图也需要隐藏/显示
|
lineView.setAlpha(1.0f);
|
||||||
} else {
|
} else {
|
||||||
startPointView.setAlpha(0.0f);
|
startPointView.setAlpha(0.0f);
|
||||||
endPointView.setAlpha(0.0f);
|
endPointView.setAlpha(0.0f);
|
||||||
lineView.setAlpha(0.0f); // 隐藏线视图
|
lineView.setAlpha(0.0f);
|
||||||
}
|
}
|
||||||
return startPointView;
|
return startPointView;
|
||||||
}
|
}
|
||||||
@ -418,7 +352,6 @@ public class FloatingViewManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 移除最后一个事件
|
|
||||||
Event lastEvent = runtimeEvents.remove(runtimeEvents.size() - 1).getEvent();
|
Event lastEvent = runtimeEvents.remove(runtimeEvents.size() - 1).getEvent();
|
||||||
removeEvent(lastEvent);
|
removeEvent(lastEvent);
|
||||||
eventOrderCounter--;
|
eventOrderCounter--;
|
||||||
@ -426,7 +359,6 @@ public class FloatingViewManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void closeFloatingViews() {
|
private void closeFloatingViews() {
|
||||||
// 停止自动点击服务
|
|
||||||
AutoClickService service = AutoClickService.getInstance();
|
AutoClickService service = AutoClickService.getInstance();
|
||||||
if (service != null) {
|
if (service != null) {
|
||||||
service.stopClicking();
|
service.stopClicking();
|
||||||
@ -435,13 +367,11 @@ public class FloatingViewManager {
|
|||||||
Toast.makeText(context, "请同意无障碍服务权限", Toast.LENGTH_SHORT).show();
|
Toast.makeText(context, "请同意无障碍服务权限", Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateTouchPointsBackground(R.drawable.ring_has_bg);
|
removeAllFloatingViews();
|
||||||
removeFloatingViews(); // 移除所有悬浮窗
|
|
||||||
|
|
||||||
context.stopService(new Intent(context, ForegroundService.class));
|
context.stopService(new Intent(context, ForegroundService.class));
|
||||||
PrefUtils.setFloatingShown(context, 0);
|
PrefUtils.setFloatingShown(context, 0);
|
||||||
|
|
||||||
// 发送浮窗关闭广播
|
|
||||||
Intent intent = new Intent("com.auto.clicker.autoclicker.FLOATING_WINDOW_STATE_CHANGED");
|
Intent intent = new Intent("com.auto.clicker.autoclicker.FLOATING_WINDOW_STATE_CHANGED");
|
||||||
intent.putExtra("isShown", false);
|
intent.putExtra("isShown", false);
|
||||||
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
|
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
|
||||||
@ -464,30 +394,8 @@ public class FloatingViewManager {
|
|||||||
updateTouchPointsBackground(R.drawable.ring_has_bg);
|
updateTouchPointsBackground(R.drawable.ring_has_bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
private WindowManager.LayoutParams createLineViewParams() {
|
|
||||||
// 创建连接线(滑动路径)的参数,全屏不可点击
|
|
||||||
int overlayType = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ?
|
|
||||||
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY :
|
|
||||||
WindowManager.LayoutParams.TYPE_PHONE;
|
|
||||||
|
|
||||||
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
|
|
||||||
WindowManager.LayoutParams.MATCH_PARENT,
|
|
||||||
WindowManager.LayoutParams.MATCH_PARENT,
|
|
||||||
overlayType,
|
|
||||||
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
|
|
||||||
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
|
|
||||||
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
|
|
||||||
PixelFormat.TRANSLUCENT
|
|
||||||
);
|
|
||||||
params.gravity = Gravity.TOP | Gravity.START;
|
|
||||||
params.x = 0;
|
|
||||||
params.y = 0;
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void removeEvent(Event event) {
|
private void removeEvent(Event event) {
|
||||||
try {
|
try {
|
||||||
// 判断类型并移除相关视图
|
|
||||||
if (event instanceof PointEvent) {
|
if (event instanceof PointEvent) {
|
||||||
PointEvent pointEvent = (PointEvent) event;
|
PointEvent pointEvent = (PointEvent) event;
|
||||||
windowManager.removeView(pointEvent.getView());
|
windowManager.removeView(pointEvent.getView());
|
||||||
@ -502,42 +410,48 @@ public class FloatingViewManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeFloatingViews() {
|
public void removeAllFloatingViews() {
|
||||||
|
removeAllEventViews();
|
||||||
|
|
||||||
|
removeMultipleControlBarView();
|
||||||
|
|
||||||
|
if (floatingTabDialogManager != null) {
|
||||||
|
floatingTabDialogManager.removeFloatingTabDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.d(TAG, "所有浮动视图(包括控制栏和事件)已移除");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeAllEventViews() {
|
||||||
try {
|
try {
|
||||||
// 移除点事件视图
|
|
||||||
for (EventWrapper wrapper : new ArrayList<>(runtimeEvents)) {
|
for (EventWrapper wrapper : new ArrayList<>(runtimeEvents)) {
|
||||||
if (wrapper.getType() == EventWrapper.EventType.POINT) {
|
if (wrapper.getType() == EventWrapper.EventType.POINT) {
|
||||||
PointEvent pe = (PointEvent) wrapper.getEvent();
|
PointEvent pe = (PointEvent) wrapper.getEvent();
|
||||||
safeRemoveView(pe.getView());
|
safeRemoveView(pe.getView());
|
||||||
}
|
} else if (wrapper.getType() == EventWrapper.EventType.SLIDE) {
|
||||||
}
|
|
||||||
|
|
||||||
// 移除滑动事件视图
|
|
||||||
for (EventWrapper wrapper : new ArrayList<>(runtimeEvents)) {
|
|
||||||
if (wrapper.getType() == EventWrapper.EventType.SLIDE) {
|
|
||||||
SlideEvent se = (SlideEvent) wrapper.getEvent();
|
SlideEvent se = (SlideEvent) wrapper.getEvent();
|
||||||
safeRemoveView(se.getStartPoint().getView());
|
safeRemoveView(se.getStartPoint().getView());
|
||||||
safeRemoveView(se.getEndPoint().getView());
|
safeRemoveView(se.getEndPoint().getView());
|
||||||
safeRemoveView(se.getLineView());
|
safeRemoveView(se.getLineView());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
runtimeEvents.clear();
|
runtimeEvents.clear();
|
||||||
|
Log.d(TAG, "所有事件悬浮窗已移除");
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "移除事件悬浮窗失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeMultipleControlBarView() {
|
||||||
|
try {
|
||||||
if (multipleControlBarView != null) {
|
if (multipleControlBarView != null) {
|
||||||
safeRemoveView(multipleControlBarView);
|
safeRemoveView(multipleControlBarView);
|
||||||
multipleControlBarView = null;
|
multipleControlBarView = null;
|
||||||
}
|
|
||||||
|
|
||||||
if (floatingTabDialogManager != null) {
|
|
||||||
floatingTabDialogManager.removeFloatingTabDialog();
|
|
||||||
}
|
|
||||||
|
|
||||||
isMultipleRunning = false;
|
isMultipleRunning = false;
|
||||||
Log.d(TAG, "悬浮窗已移除");
|
Log.d(TAG, "多选控制栏悬浮窗已移除");
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(TAG, "移除悬浮窗失败", e);
|
Log.e(TAG, "移除多选控制栏悬浮窗失败", e);
|
||||||
isMultipleRunning = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -574,156 +488,7 @@ public class FloatingViewManager {
|
|||||||
context.startActivity(intent);
|
context.startActivity(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isDebounced() {
|
|
||||||
long currentTime = System.currentTimeMillis();
|
|
||||||
if (currentTime - lastToggleTime < DEBOUNCE_INTERVAL) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
lastToggleTime = currentTime;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
|
||||||
private void setupDraggablePoint(TextView point, WindowManager.LayoutParams params, PointEvent pointEvent) {
|
|
||||||
point.setOnTouchListener(new View.OnTouchListener() {
|
|
||||||
private float lastX, lastY;
|
|
||||||
private float paramX, paramY;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onTouch(View v, MotionEvent event) {
|
|
||||||
if (isMultipleRunning) {
|
|
||||||
if (event.getAction() == MotionEvent.ACTION_UP) {
|
|
||||||
v.performClick();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
pointEvent.setX(params.x);
|
|
||||||
pointEvent.setY(params.y);
|
|
||||||
windowManager.updateViewLayout(point, params);
|
|
||||||
updateServicePositions();
|
|
||||||
return true;
|
|
||||||
case MotionEvent.ACTION_UP:
|
|
||||||
v.performClick();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
|
||||||
private void setupDraggableSlidePoint(TextView point, WindowManager.LayoutParams params,
|
|
||||||
PointEvent pointEvent, SlideEvent slideEvent) {
|
|
||||||
point.setOnTouchListener(new View.OnTouchListener() {
|
|
||||||
private float lastX, lastY;
|
|
||||||
private float paramX, paramY;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onTouch(View v, MotionEvent event) {
|
|
||||||
if (isMultipleRunning) {
|
|
||||||
if (event.getAction() == MotionEvent.ACTION_UP) {
|
|
||||||
v.performClick();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
pointEvent.setX(params.x);
|
|
||||||
pointEvent.setY(params.y);
|
|
||||||
windowManager.updateViewLayout(point, params);
|
|
||||||
|
|
||||||
updateLinePosition(slideEvent);
|
|
||||||
updateServicePositions();
|
|
||||||
return true;
|
|
||||||
case MotionEvent.ACTION_UP:
|
|
||||||
v.performClick();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateLinePosition(SlideEvent slideEvent) {
|
|
||||||
PointEvent start = slideEvent.getStartPoint();
|
|
||||||
PointEvent end = slideEvent.getEndPoint();
|
|
||||||
ConnectingLineView lineView = slideEvent.getLineView();
|
|
||||||
|
|
||||||
if (lineView == null) {
|
|
||||||
Log.e(TAG, "updateLinePosition: lineView is null, cannot update line");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
float startCenterX = start.getX() + (float) TOUCH_POINT_SIZE / 2;
|
|
||||||
float startCenterY = start.getY() + (float) TOUCH_POINT_SIZE / 2;
|
|
||||||
float endCenterX = end.getX() + (float) TOUCH_POINT_SIZE / 2;
|
|
||||||
float endCenterY = end.getY() + (float) TOUCH_POINT_SIZE / 2;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
private WindowManager.LayoutParams createTouchPointParams() {
|
|
||||||
// 创建点击点的布局参数
|
|
||||||
int overlayType = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ?
|
|
||||||
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY :
|
|
||||||
WindowManager.LayoutParams.TYPE_PHONE;
|
|
||||||
|
|
||||||
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
|
|
||||||
TOUCH_POINT_SIZE, TOUCH_POINT_SIZE,
|
|
||||||
overlayType,
|
|
||||||
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
|
|
||||||
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
|
|
||||||
PixelFormat.TRANSLUCENT
|
|
||||||
);
|
|
||||||
params.gravity = Gravity.TOP | Gravity.START;
|
|
||||||
return params;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateServicePositions() {
|
private void updateServicePositions() {
|
||||||
// 更新服务中记录的位置
|
|
||||||
AutoClickService service = AutoClickService.getInstance();
|
AutoClickService service = AutoClickService.getInstance();
|
||||||
if (service != null) {
|
if (service != null) {
|
||||||
service.addMultipleClickEvents(runtimeEvents);
|
service.addMultipleClickEvents(runtimeEvents);
|
||||||
@ -871,7 +636,7 @@ public class FloatingViewManager {
|
|||||||
public void onComplete(SolutionWithEventsAndPoints solutionData) {
|
public void onComplete(SolutionWithEventsAndPoints solutionData) {
|
||||||
new Handler(Looper.getMainLooper()).post(() -> {
|
new Handler(Looper.getMainLooper()).post(() -> {
|
||||||
if (solutionData != null && solutionData.events != null) {
|
if (solutionData != null && solutionData.events != null) {
|
||||||
removeFloatingViews();
|
removeAllEventViews();
|
||||||
runtimeEvents.clear();
|
runtimeEvents.clear();
|
||||||
eventOrderCounter = 1;
|
eventOrderCounter = 1;
|
||||||
|
|
||||||
@ -883,50 +648,31 @@ public class FloatingViewManager {
|
|||||||
TouchPoint clickPoint = eventWithPoints.clickTouchPoint;
|
TouchPoint clickPoint = eventWithPoints.clickTouchPoint;
|
||||||
if (clickPoint != null) {
|
if (clickPoint != null) {
|
||||||
PointEvent pointEvent = new PointEvent(eventEntity.orderInSolution, clickPoint.x, clickPoint.y);
|
PointEvent pointEvent = new PointEvent(eventEntity.orderInSolution, clickPoint.x, clickPoint.y);
|
||||||
TextView pointView = createTouchPointView(String.valueOf(pointEvent.getId()));
|
|
||||||
WindowManager.LayoutParams params = createTouchPointParams();
|
EventViewBinder.bindPoint(context, windowManager,
|
||||||
params.x = pointEvent.getX();
|
pointEvent,
|
||||||
params.y = pointEvent.getY();
|
TOUCH_POINT_SIZE,
|
||||||
pointView.setLayoutParams(params);
|
screenWidth, screenHeight,
|
||||||
pointEvent.setView(pointView);
|
(x, y) -> updateServicePositions(), eventEntity.orderInSolution);
|
||||||
setupDraggablePoint(pointView, params, pointEvent);
|
|
||||||
windowManager.addView(pointView, params);
|
|
||||||
runtimeEvents.add(new EventWrapper(type, pointEvent, pointEvent.getId()));
|
runtimeEvents.add(new EventWrapper(type, pointEvent, pointEvent.getId()));
|
||||||
}
|
}
|
||||||
} else if (type == EventWrapper.EventType.SLIDE) {
|
} else if (type == EventWrapper.EventType.SLIDE) {
|
||||||
TouchPoint startPointData = eventWithPoints.slideStartTouchPoint;
|
TouchPoint startPointData = eventWithPoints.slideStartTouchPoint;
|
||||||
TouchPoint endPointData = eventWithPoints.slideEndTouchPoint;
|
TouchPoint endPointData = eventWithPoints.slideEndTouchPoint;
|
||||||
|
|
||||||
if (startPointData != null && endPointData != null) {
|
if (startPointData != null && endPointData != null) {
|
||||||
PointEvent startPointEvent = new PointEvent(eventEntity.orderInSolution, startPointData.x, startPointData.y);
|
PointEvent startPointEvent = new PointEvent(eventEntity.orderInSolution, startPointData.x, startPointData.y);
|
||||||
PointEvent endPointEvent = new PointEvent(eventEntity.orderInSolution, endPointData.x, endPointData.y);
|
PointEvent endPointEvent = new PointEvent(eventEntity.orderInSolution, endPointData.x, endPointData.y);
|
||||||
|
|
||||||
TextView startPointView = createTouchPointView(String.valueOf(startPointEvent.getId()));
|
|
||||||
WindowManager.LayoutParams startParams = createTouchPointParams();
|
|
||||||
startParams.x = startPointEvent.getX();
|
|
||||||
startParams.y = startPointEvent.getY();
|
|
||||||
startPointView.setLayoutParams(startParams);
|
|
||||||
|
|
||||||
TextView endPointView = createTouchPointView(String.valueOf(endPointEvent.getId()));
|
|
||||||
WindowManager.LayoutParams endParams = createTouchPointParams();
|
|
||||||
endParams.x = endPointEvent.getX();
|
|
||||||
endParams.y = endPointEvent.getY();
|
|
||||||
endPointView.setLayoutParams(endParams);
|
|
||||||
|
|
||||||
ConnectingLineView lineView = new ConnectingLineView(context);
|
|
||||||
WindowManager.LayoutParams lineParams = createLineViewParams();
|
|
||||||
|
|
||||||
SlideEvent slideEvent = new SlideEvent(eventEntity.orderInSolution, startPointEvent, endPointEvent);
|
SlideEvent slideEvent = new SlideEvent(eventEntity.orderInSolution, startPointEvent, endPointEvent);
|
||||||
slideEvent.setLineView(lineView);
|
|
||||||
slideEvent.setLineParams(lineParams);
|
|
||||||
|
|
||||||
setupDraggableSlidePoint(startPointView, startParams, startPointEvent, slideEvent);
|
EventViewBinder.bindSlide(context, windowManager,
|
||||||
setupDraggableSlidePoint(endPointView, endParams, endPointEvent, slideEvent);
|
slideEvent,
|
||||||
|
TOUCH_POINT_SIZE,
|
||||||
|
screenWidth, screenHeight,
|
||||||
|
(x, y) -> updateServicePositions(), eventEntity.orderInSolution);
|
||||||
|
|
||||||
windowManager.addView(lineView, lineParams);
|
|
||||||
windowManager.addView(startPointView, startParams);
|
|
||||||
windowManager.addView(endPointView, endParams);
|
|
||||||
|
|
||||||
updateLinePosition(slideEvent);
|
|
||||||
runtimeEvents.add(new EventWrapper(type, slideEvent, slideEvent.getId()));
|
runtimeEvents.add(new EventWrapper(type, slideEvent, slideEvent.getId()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -960,4 +706,13 @@ public class FloatingViewManager {
|
|||||||
callback.onError(new IllegalStateException("EventRepository not initialized."));
|
callback.onError(new IllegalStateException("EventRepository not initialized."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isDebounced() {
|
||||||
|
long currentTime = System.currentTimeMillis();
|
||||||
|
if (currentTime - lastToggleTime < DEBOUNCE_INTERVAL) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
lastToggleTime = currentTime;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user