初步实现单点点击

This commit is contained in:
lihongwei 2025-04-23 13:54:09 +08:00
parent ee36b43981
commit e5f52aaba3
10 changed files with 176 additions and 220 deletions

View File

@ -8,7 +8,7 @@ android {
defaultConfig {
applicationId = "com.auto.autoclicker"
minSdk = 23
minSdk = 24
targetSdk = 35
versionCode = 1
versionName = "1.0.0"

View File

@ -2,119 +2,103 @@ package com.auto.autoclicker;
import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.GestureDescription;
import android.content.Intent;
import android.graphics.Path;
import android.os.Build;
import android.graphics.Point;
import android.os.Handler;
import android.os.Looper;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.accessibility.AccessibilityEvent;
/**
* 无障碍服务执行自动点击操作
*/
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
public class AutoClickService extends AccessibilityService {
private static final String TAG = "AutoClickService";
private static volatile AutoClickService instance;
private static final long MIN_CLICK_INTERVAL = 100;
private static final long MAX_CLICK_INTERVAL = 10000;
private static final int MIN_CLICK_DURATION = 50;
private static final int MAX_CLICK_DURATION = 1000;
private final Handler handler = new Handler(Looper.getMainLooper());
private boolean isClicking = false;
private int clickX = 500;
private int clickY = 500;
private long clickInterval = 1000; // 默认1秒间隔
private int clickDuration = 200; // 默认200毫秒点击时长
private int screenWidth, screenHeight;
private long clickInterval = 1000;
private int clickDuration = 200;
private int screenWidth;
private int screenHeight;
@Override
public void onCreate() {
super.onCreate();
instance = this;
// 获取屏幕尺寸
DisplayMetrics metrics = getResources().getDisplayMetrics();
screenWidth = metrics.widthPixels;
screenHeight = metrics.heightPixels;
Log.d(TAG, "屏幕尺寸: " + screenWidth + "x" + screenHeight);
Point screenSize = ScreenUtils.getScreenSize(this);
screenWidth = screenSize.x;
screenHeight = screenSize.y;
logDebug("屏幕尺寸: " + screenWidth + "x" + screenHeight);
}
public static AutoClickService getInstance() {
return instance;
return null;
}
/**
* 设置点击位置
*/
public void setClickPosition(float x, float y) {
this.clickX = (int) Math.max(0, Math.min(x, screenWidth));
this.clickY = (int) Math.max(0, Math.min(y, screenHeight));
Log.d(TAG, "点击位置设置为: (" + clickX + ", " + clickY + ")");
Log.d(TAG, "设置点击位置为: (" + clickX + ", " + clickY + "), 屏幕尺寸: " + screenWidth + "x" + screenHeight);
Point constrainedPoint = ViewUtils.constrainToScreen(x, y, screenWidth, screenHeight);
this.clickX = constrainedPoint.x;
this.clickY = constrainedPoint.y;
logDebug("设置点击位置: x=" + x + ", y=" + y + ", 修正后: (" + clickX + ", " + clickY + ")");
}
/**
* 设置点击间隔
*/
public void setClickInterval(long interval) {
if (interval > 0) {
this.clickInterval = interval;
Log.d(TAG, "点击间隔设置为: " + interval + "ms");
if (interval < MIN_CLICK_INTERVAL || interval > MAX_CLICK_INTERVAL) {
Log.w(TAG, "点击间隔超出合理范围: " + interval + "ms");
return;
}
this.clickInterval = interval;
logDebug("点击间隔设置为: " + interval + "ms");
}
/**
* 设置点击时长
*/
public void setClickDuration(int duration) {
if (duration > 0) {
this.clickDuration = duration;
Log.d(TAG, "点击时长设置为: " + duration + "ms");
if (duration < MIN_CLICK_DURATION || duration > MAX_CLICK_DURATION) {
Log.w(TAG, "点击时长超出合理范围: " + duration + "ms");
return;
}
this.clickDuration = duration;
logDebug("点击时长设置为: " + duration + "ms");
}
/**
* 开始自动点击
*/
public void startClicking() {
if (!isClicking) {
isClicking = true;
performClick();
Log.d(TAG, "开始点击: (" + clickX + ", " + clickY + ")");
logDebug("开始点击: (" + clickX + ", " + clickY + ")");
}
}
/**
* 停止自动点击
*/
public void stopClicking() {
if (isClicking) {
isClicking = false;
handler.removeCallbacksAndMessages(null);
Log.d(TAG, "停止点击");
logDebug("停止点击");
}
}
/**
* 执行单次点击
*/
private void performClick() {
if (!isClicking || Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
Log.w(TAG, "点击被跳过(未开始或系统版本不支持");
if (!isClicking) {
logDebug("点击被跳过(未开始)");
return;
}
logDebug("执行点击: (" + clickX + ", " + clickY + ")");
Path path = new Path();
path.moveTo(clickX, clickY);
path.lineTo(clickX, clickY); // 创建一个点状路径
GestureDescription.StrokeDescription stroke =
new GestureDescription.StrokeDescription(path, 0, 10); // 10ms 点击
new GestureDescription.StrokeDescription(path, 0, clickDuration);
GestureDescription gesture =
new GestureDescription.Builder().addStroke(stroke).build();
dispatchGesture(gesture, new GestureResultCallback() {
@Override
public void onCompleted(GestureDescription gestureDescription) {
super.onCompleted(gestureDescription);
Log.i(TAG, "点击完成: (" + clickX + ", " + clickY + ")");
logDebug("点击完成: (" + clickX + ", " + clickY + ")");
if (isClicking) {
handler.postDelayed(() -> performClick(), clickInterval);
}
@ -122,78 +106,44 @@ public class AutoClickService extends AccessibilityService {
@Override
public void onCancelled(GestureDescription gestureDescription) {
super.onCancelled(gestureDescription);
Log.e(TAG, "点击取消(可能位置错误或界面变化): (" + clickX + ", " + clickY + ")");
Log.e(TAG, "点击取消: (" + clickX + ", " + clickY + ")");
if (isClicking) {
handler.postDelayed(() -> performClick(), clickInterval + 300); // 稍微延迟重试
handler.postDelayed(() -> performClick(), clickInterval + 300);
}
}
}, null);
}
public void testSingleClick(float x, float y) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
Log.e(TAG, "设备不支持手势(需要 API 24+");
return;
}
try {
Path path = new Path();
path.moveTo(x, y);
path.lineTo(x, y); // 明确指定按下和抬起
Log.d(TAG, "测试点击: (" + x + ", " + y + ")");
GestureDescription.StrokeDescription stroke = new GestureDescription.StrokeDescription(
path, 0, 100
);
GestureDescription gesture = new GestureDescription.Builder()
.addStroke(stroke)
.build();
boolean dispatched = dispatchGesture(gesture, new GestureResultCallback() {
@Override
public void onCompleted(GestureDescription gestureDescription) {
Log.v(TAG, "测试点击完成: (" + x + ", " + y + ")");
}
@Override
public void onCancelled(GestureDescription gestureDescription) {
Log.w(TAG, "测试点击取消: (" + x + ", " + y + ")");
}
}, null);
Log.d(TAG, "手势分发结果: " + (dispatched ? "成功" : "失败"));
} catch (Exception e) {
Log.e(TAG, "测试点击失败", e);
}
}
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
// 不处理事件
}
@Override
public void onInterrupt() {
stopClicking();
Log.d(TAG, "无障碍服务中断");
logDebug("无障碍服务中断");
}
@Override
protected void onServiceConnected() {
super.onServiceConnected();
Log.d(TAG, "无障碍服务已连接");
}
public boolean isClicking() {
return isClicking;
logDebug("无障碍服务已连接");
}
@Override
public void onDestroy() {
super.onDestroy();
stopClicking();
instance = null;
Log.d(TAG, "无障碍服务已销毁");
Intent intent = new Intent("com.auto.autoclicker.SERVICE_DESTROYED");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
logDebug("无障碍服务已销毁");
}
public boolean isClicking() {
return isClicking;
}
private void logDebug(String message) {
Log.d(TAG, message);
}
}

View File

@ -1,11 +1,11 @@
package com.auto.autoclicker;
import android.content.Context;
import android.graphics.Color;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.os.Build;
import android.provider.Settings;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
@ -16,11 +16,9 @@ import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Toast;
/**
* 悬浮窗管理器负责触摸点和控制栏的显示与交互
*/
public class FloatingViewManager {
private static final String TAG = "FloatingViewManager";
private static final long DEBOUNCE_INTERVAL = 500;
private final Context context;
private final WindowManager windowManager;
private View touchPointView;
@ -30,32 +28,28 @@ public class FloatingViewManager {
private float touchPointX = 500;
private float touchPointY = 500;
private boolean isClicking = false;
private int screenWidth, screenHeight;
private boolean isFloatingViewsShown = false;
private long lastToggleTime = 0;
private static final long DEBOUNCE_INTERVAL = 500;
private static final int CONTROL_BAR_WIDTH = 200; // 假设控制栏宽度
private static final int CONTROL_BAR_HEIGHT = 100; // 假设控制栏高度
private final int screenWidth;
private final int screenHeight;
public FloatingViewManager(Context context) {
this.context = context;
this.windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
screenWidth = metrics.widthPixels;
screenHeight = metrics.heightPixels;
Log.d(TAG, "屏幕尺寸: " + screenWidth + "x" + screenHeight);
Point screenSize = ScreenUtils.getScreenSize(context);
this.screenWidth = screenSize.x;
this.screenHeight = screenSize.y;
logDebug("屏幕尺寸: " + screenWidth + "x" + screenHeight);
}
/**
* 显示悬浮窗触摸点和控制栏
*/
public void showFloatingViews() throws SecurityException {
if (!Settings.canDrawOverlays(context)) {
throw new SecurityException("需要悬浮窗权限");
}
if (touchPointView != null || controlBarView != null) {
Log.w(TAG, "悬浮窗已存在,跳过创建");
return;
if (isFloatingViewsShown) {
logDebug("悬浮窗已存在,清理后重新创建");
removeFloatingViews();
}
initializeTouchPointView();
@ -63,15 +57,13 @@ public class FloatingViewManager {
windowManager.addView(touchPointView, touchPointParams);
windowManager.addView(controlBarView, controlBarParams);
Log.d(TAG, "悬浮窗已添加");
isFloatingViewsShown = true;
logDebug("悬浮窗已添加");
}
/**
* 初始化触摸点视图
*/
private void initializeTouchPointView() {
touchPointView = new View(context);
touchPointView.setBackgroundResource(R.drawable.shoot); // 使用触摸点图标
touchPointView.setBackgroundResource(R.drawable.un_touch_point);
touchPointParams = new WindowManager.LayoutParams(
100, 100,
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ?
@ -81,7 +73,7 @@ public class FloatingViewManager {
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
PixelFormat.TRANSLUCENT
);
touchPointParams.gravity = Gravity.TOP | Gravity.LEFT;
touchPointParams.gravity = Gravity.TOP | Gravity.START;
touchPointParams.x = (int) touchPointX;
touchPointParams.y = (int) touchPointY;
@ -101,15 +93,11 @@ public class FloatingViewManager {
case MotionEvent.ACTION_MOVE:
float dx = event.getRawX() - lastX;
float dy = event.getRawY() - lastY;
touchPointParams.x = (int) Math.max(0, Math.min(paramX + dx, screenWidth - 100));
touchPointParams.y = (int) Math.max(0, Math.min(paramY + dy, screenHeight - 100));
touchPointX = touchPointParams.x;
touchPointY = touchPointParams.y;
windowManager.updateViewLayout(touchPointView, touchPointParams);
updateTouchPointPosition(paramX, paramY, dx, dy);
AutoClickService service = AutoClickService.getInstance();
if (service != null) {
service.setClickPosition(touchPointX + 50, touchPointY + 50);
Log.d(TAG, "触摸点移动到: (" + touchPointX + ", " + touchPointY + ")");
logDebug("触摸点移动到: (" + touchPointX + ", " + touchPointY + ")");
}
break;
}
@ -118,9 +106,16 @@ public class FloatingViewManager {
});
}
/**
* 初始化控制栏视图
*/
private void updateTouchPointPosition(float paramX, float paramY, float dx, float dy) {
Point constrainedPoint = ViewUtils.constrainToScreen(
paramX + dx, paramY + dy, screenWidth - touchPointView.getWidth(), screenHeight - touchPointView.getHeight());
touchPointParams.x = constrainedPoint.x;
touchPointParams.y = constrainedPoint.y;
touchPointX = touchPointParams.x;
touchPointY = touchPointParams.y;
windowManager.updateViewLayout(touchPointView, touchPointParams);
}
private void initializeControlBarView() {
controlBarView = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.control_bar, null);
controlBarParams = new WindowManager.LayoutParams(
@ -133,11 +128,10 @@ public class FloatingViewManager {
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
PixelFormat.TRANSLUCENT
);
controlBarParams.gravity = Gravity.TOP | Gravity.LEFT;
controlBarParams.gravity = Gravity.TOP | Gravity.START;
controlBarParams.x = 0;
controlBarParams.y = 200;
// 替换 controlBarView onTouchListener toggleButton OnClickListener
controlBarView.setOnTouchListener(new View.OnTouchListener() {
private float lastX, lastY;
private float paramX, paramY;
@ -154,9 +148,7 @@ public class FloatingViewManager {
case MotionEvent.ACTION_MOVE:
float dx = event.getRawX() - lastX;
float dy = event.getRawY() - lastY;
controlBarParams.x = (int) Math.max(0, Math.min(paramX + dx, screenWidth - CONTROL_BAR_WIDTH));
controlBarParams.y = (int) Math.max(0, Math.min(paramY + dy, screenHeight - CONTROL_BAR_HEIGHT));
windowManager.updateViewLayout(controlBarView, controlBarParams);
updateControlBarPosition(paramX, paramY, dx, dy);
return true;
}
return false;
@ -165,50 +157,55 @@ public class FloatingViewManager {
Button toggleButton = controlBarView.findViewById(R.id.toggle_button);
toggleButton.setOnClickListener(v -> {
long currentTime = System.currentTimeMillis();
if (currentTime - lastToggleTime < DEBOUNCE_INTERVAL) {
if (!isDebounced()) {
return;
}
lastToggleTime = currentTime;
AutoClickService service = AutoClickService.getInstance();
if (service == null) {
Log.e(TAG, "AutoClickService 未初始化");
Toast.makeText(context, "请启用无障碍服务", Toast.LENGTH_SHORT).show();
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();
toggleButton.setText(R.string.start_click);
touchPointView.setBackgroundResource(R.drawable.shoot);
touchPointView.setBackgroundResource(R.drawable.un_touch_point);
Toast.makeText(context, "停止自动点击", Toast.LENGTH_SHORT).show();
} else {
service.setClickPosition(touchPointX + 50, touchPointY + 50);
service.startClicking();
toggleButton.setText(R.string.stop_click);
touchPointView.setBackgroundColor(Color.GREEN);
touchPointView.setBackgroundResource(R.drawable.touch_point);
Toast.makeText(context, "开始自动点击", Toast.LENGTH_SHORT).show();
}
isClicking = !isClicking;
// 测试单次点击屏幕中央
float testX = screenWidth / 2f;
float testY = screenHeight / 2f;
service.testSingleClick(testX, testY);
Toast.makeText(context, "测试点击: (" + testX + ", " + testY + ")", Toast.LENGTH_SHORT).show();
Log.d(TAG, "AutoClickService 实例:" + service);
Log.d(TAG, "服务是否点击中:" + service.isClicking());
logDebug("服务是否点击中: " + service.isClicking());
});
}
/**
* 移除悬浮窗
*/
private void updateControlBarPosition(float paramX, float paramY, float dx, float dy) {
Point constrainedPoint = ViewUtils.constrainToScreen(
paramX + dx, paramY + dy, screenWidth - controlBarView.getWidth(), screenHeight - controlBarView.getHeight());
controlBarParams.x = constrainedPoint.x;
controlBarParams.y = constrainedPoint.y;
windowManager.updateViewLayout(controlBarView, controlBarParams);
}
private boolean isDebounced() {
long currentTime = System.currentTimeMillis();
if (currentTime - lastToggleTime < DEBOUNCE_INTERVAL) {
return false;
}
lastToggleTime = currentTime;
return true;
}
public void removeFloatingViews() {
try {
if (touchPointView != null) {
@ -219,9 +216,15 @@ public class FloatingViewManager {
windowManager.removeView(controlBarView);
controlBarView = null;
}
Log.d(TAG, "悬浮窗已移除");
isFloatingViewsShown = false;
logDebug("悬浮窗已移除");
} catch (Exception e) {
Log.e(TAG, "移除悬浮窗失败", e);
isFloatingViewsShown = false;
}
}
private void logDebug(String message) {
Log.d(TAG, message);
}
}

View File

@ -12,9 +12,6 @@ import android.util.Log;
import androidx.core.app.NotificationCompat;
/**
* 前台服务管理自动点击的悬浮窗和通知
*/
public class ForegroundService extends Service {
private static final String TAG = "ForegroundService";
private static final String CHANNEL_ID = "AutoClickerChannel";
@ -36,7 +33,6 @@ public class ForegroundService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 创建通知
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(
this, 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE

View File

@ -15,16 +15,13 @@ import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AppCompatActivity;
/**
* 主活动负责权限检查和控制悬浮窗显示/隐藏
*/
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private Button startButton;
private ActivityResultLauncher<Intent> permissionLauncher;
private boolean isFloatingShown = false;
private long lastClickTime = 0;
private static final long DEBOUNCE_INTERVAL = 500; // 防抖间隔毫秒
private static final long DEBOUNCE_INTERVAL = 500;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -34,22 +31,16 @@ public class MainActivity extends AppCompatActivity {
startButton = findViewById(R.id.start_Button);
startButton.setOnClickListener(v -> toggleFloatingWindow());
// 初始化权限请求回调
permissionLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> checkPermissions());
// 同步服务状态
syncServiceState();
checkPermissions();
}
/**
* 检查必要的权限无障碍服务悬浮窗电池优化
*/
private void checkPermissions() {
boolean allPermissionsGranted = true;
// 检查无障碍服务
if (!isAccessibilityServiceEnabled()) {
if (isAccessibilityServiceEnabled()) {
allPermissionsGranted = false;
try {
Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
@ -60,8 +51,7 @@ public class MainActivity extends AppCompatActivity {
}
}
// 检查悬浮窗权限
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) {
if (!Settings.canDrawOverlays(this)) {
allPermissionsGranted = false;
try {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
@ -72,30 +62,23 @@ public class MainActivity extends AppCompatActivity {
}
}
// 检查电池优化
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
if (!pm.isIgnoringBatteryOptimizations(getPackageName())) {
allPermissionsGranted = false;
try {
Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:" + getPackageName()));
permissionLauncher.launch(intent);
Toast.makeText(this, "请禁用电池优化", Toast.LENGTH_LONG).show();
} catch (Exception e) {
Toast.makeText(this, "无法打开电池优化设置", Toast.LENGTH_LONG).show();
}
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
if (!pm.isIgnoringBatteryOptimizations(getPackageName())) {
allPermissionsGranted = false;
try {
Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:" + getPackageName()));
permissionLauncher.launch(intent);
Toast.makeText(this, "请禁用电池优化", Toast.LENGTH_LONG).show();
} catch (Exception e) {
Toast.makeText(this, "无法打开电池优化设置", Toast.LENGTH_LONG).show();
}
}
// 更新按钮状态
startButton.setEnabled(allPermissionsGranted);
updateButtonText();
}
/**
* 检查无障碍服务是否启用
*/
private boolean isAccessibilityServiceEnabled() {
String service = getPackageName() + "/" + AutoClickService.class.getCanonicalName();
try {
@ -106,47 +89,37 @@ public class MainActivity extends AppCompatActivity {
String settingValue = Settings.Secure.getString(
getContentResolver(),
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
return settingValue != null && settingValue.contains(service);
return settingValue == null || !settingValue.contains(service);
}
} catch (Settings.SettingNotFoundException e) {
e.printStackTrace();
}
return false;
return true;
}
/**
* 同步服务状态从通知栏进入时
*/
private void syncServiceState() {
isFloatingShown = isServiceRunning(ForegroundService.class);
isFloatingShown = isServiceRunning();
updateButtonText();
}
/**
* 检查服务是否运行
*/
private boolean isServiceRunning(Class<?> serviceClass) {
private boolean isServiceRunning() {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
if (ForegroundService.class.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
/**
* 切换悬浮窗显示/隐藏
*/
private void toggleFloatingWindow() {
// 防抖处理
long currentTime = System.currentTimeMillis();
if (currentTime - lastClickTime < DEBOUNCE_INTERVAL) {
return;
}
lastClickTime = currentTime;
if (!isAccessibilityServiceEnabled() || !Settings.canDrawOverlays(this)) {
if (isAccessibilityServiceEnabled() || !Settings.canDrawOverlays(this)) {
Toast.makeText(this, "请授予所有必要权限", Toast.LENGTH_LONG).show();
checkPermissions();
return;
@ -169,9 +142,6 @@ public class MainActivity extends AppCompatActivity {
updateButtonText();
}
/**
* 更新按钮文本
*/
private void updateButtonText() {
startButton.setText(isFloatingShown ? R.string.hide_floating_window : R.string.show_floating_window);
}

View File

@ -0,0 +1,14 @@
package com.auto.autoclicker;
import android.content.Context;
import android.graphics.Point;
import android.util.DisplayMetrics;
public class ScreenUtils {
public static Point getScreenSize(Context context) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
return new Point(metrics.widthPixels, metrics.heightPixels);
}
}

View File

@ -0,0 +1,13 @@
package com.auto.autoclicker;
import android.graphics.Point;
public class ViewUtils {
public static Point constrainToScreen(float x, float y, int maxWidth, int maxHeight) {
int constrainedX = (int) Math.max(0, Math.min(x, maxWidth));
int constrainedY = (int) Math.max(0, Math.min(y, maxHeight));
return new Point(constrainedX, constrainedY);
}
}

View File

@ -5,5 +5,5 @@
android:viewportHeight="1024">
<path
android:pathData="M502.7,448a56,56 0,1 0,0 112,56 56,0 0,0 0,-112zM502.7,96C277.3,96 94.6,278.7 94.6,504S277.3,912 502.6,912C728,912 910.7,729.3 910.7,504S728,96 502.7,96zM544,829.3L544,688h-80v141.3C320,811.1 195.5,688 177.3,544L320,544v-80h-142.7C195.5,320 320,196.8 464,178.7L464,320h80v-141.3C688,196.8 809.8,320 828,464L688,464v80h140C809.8,688 688,811.2 544,829.3z"
android:fillColor="#565D64"/>
android:fillColor="#FF0057"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:pathData="M502.7,448a56,56 0,1 0,0 112,56 56,0 0,0 0,-112zM502.7,96C277.3,96 94.6,278.7 94.6,504S277.3,912 502.6,912C728,912 910.7,729.3 910.7,504S728,96 502.7,96zM544,829.3L544,688h-80v141.3C320,811.1 195.5,688 177.3,544L320,544v-80h-142.7C195.5,320 320,196.8 464,178.7L464,320h80v-141.3C688,196.8 809.8,320 828,464L688,464v80h140C809.8,688 688,811.2 544,829.3z"
android:fillColor="#565D64"/>
</vector>

View File

@ -1,8 +1,9 @@
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeAllMask"
android:accessibilityFeedbackType="feedbackGeneric"
android:accessibilityFeedbackType="feedbackAllMask"
android:accessibilityFlags="flagDefault|flagRequestTouchExplorationMode|flagRequestEnhancedWebAccessibility|flagReportViewIds"
android:canRetrieveWindowContent="true"
android:canPerformGestures="true"
android:description="@string/accessibility_service_description"
android:notificationTimeout="100"
android:packageNames="com.auto.autoclicker" />