完善单个点击

This commit is contained in:
lihongwei 2025-04-23 17:10:20 +08:00
parent e5f52aaba3
commit 60d264e131
14 changed files with 314 additions and 100 deletions

View File

@ -12,14 +12,21 @@ import android.view.accessibility.AccessibilityEvent;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import com.auto.autoclicker.util.ScreenUtils;
import com.auto.autoclicker.util.ViewUtils;
public class AutoClickService extends AccessibilityService {
private static final String TAG = "AutoClickService";
private static final long MIN_CLICK_INTERVAL = 100;
private static AutoClickService instance;
private static final long MIN_CLICK_INTERVAL = 40;
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;
@ -30,46 +37,69 @@ public class AutoClickService extends AccessibilityService {
@Override
public void onCreate() {
super.onCreate();
instance = this;
Point screenSize = ScreenUtils.getScreenSize(this);
screenWidth = screenSize.x;
screenHeight = screenSize.y;
logDebug("屏幕尺寸: " + screenWidth + "x" + screenHeight);
}
@Override
public void onServiceConnected() {
super.onServiceConnected();
logDebug("无障碍服务已连接");
}
@Override
public void onInterrupt() {
stopClicking();
logDebug("无障碍服务中断");
}
@Override
public void onDestroy() {
super.onDestroy();
instance = null;
stopClicking();
Intent intent = new Intent("com.auto.autoclicker.SERVICE_DESTROYED");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
logDebug("无障碍服务已销毁");
}
public static AutoClickService getInstance() {
return null;
return instance;
}
public void setClickPosition(float x, float y) {
Point constrainedPoint = ViewUtils.constrainToScreen(x, y, screenWidth, screenHeight);
this.clickX = constrainedPoint.x;
this.clickY = constrainedPoint.y;
logDebug("设置点击位置: x=" + x + ", y=" + y + ", 修正后: (" + clickX + ", " + clickY + ")");
Point constrained = ViewUtils.constrainToScreen(x, y, screenWidth, screenHeight);
this.clickX = constrained.x;
this.clickY = constrained.y;
logDebug("设置点击位置: 原始 (" + x + ", " + y + ") -> 修正 (" + clickX + ", " + clickY + ")");
}
public void setClickInterval(long interval) {
if (interval < MIN_CLICK_INTERVAL || interval > MAX_CLICK_INTERVAL) {
Log.w(TAG, "点击间隔超出合理范围: " + interval + "ms");
Log.w(TAG, "点击间隔超出范围: " + interval + "ms");
return;
}
this.clickInterval = interval;
logDebug("点击间隔设置为: " + interval + "ms");
logDebug("设置点击间隔: " + interval + "ms");
}
public void setClickDuration(int duration) {
if (duration < MIN_CLICK_DURATION || duration > MAX_CLICK_DURATION) {
Log.w(TAG, "点击时长超出合理范围: " + duration + "ms");
Log.w(TAG, "点击时长超出范围: " + duration + "ms");
return;
}
this.clickDuration = duration;
logDebug("点击时长设置为: " + duration + "ms");
logDebug("设置点击时长: " + duration + "ms");
}
public void startClicking() {
if (!isClicking) {
isClicking = true;
logDebug("开始自动点击");
performClick();
logDebug("开始点击: (" + clickX + ", " + clickY + ")");
}
}
@ -77,17 +107,23 @@ public class AutoClickService extends AccessibilityService {
if (isClicking) {
isClicking = false;
handler.removeCallbacksAndMessages(null);
logDebug("停止点击");
logDebug("停止自动点击");
}
}
public boolean isClicking() {
return isClicking;
}
private void performClick() {
if (!isClicking) {
logDebug("点击被跳过(未开始)");
logDebug("跳过点击:服务未处于运行中");
return;
}
logDebug("执行点击: (" + clickX + ", " + clickY + ")");
flashTouchFeedback();
Path path = new Path();
path.moveTo(clickX, clickY);
GestureDescription.StrokeDescription stroke =
@ -98,7 +134,7 @@ public class AutoClickService extends AccessibilityService {
dispatchGesture(gesture, new GestureResultCallback() {
@Override
public void onCompleted(GestureDescription gestureDescription) {
logDebug("点击完成: (" + clickX + ", " + clickY + ")");
logDebug("点击完成");
if (isClicking) {
handler.postDelayed(() -> performClick(), clickInterval);
}
@ -106,7 +142,7 @@ public class AutoClickService extends AccessibilityService {
@Override
public void onCancelled(GestureDescription gestureDescription) {
Log.e(TAG, "点击取消: (" + clickX + ", " + clickY + ")");
Log.e(TAG, "点击取消");
if (isClicking) {
handler.postDelayed(() -> performClick(), clickInterval + 300);
}
@ -114,35 +150,17 @@ public class AutoClickService extends AccessibilityService {
}, null);
}
private void flashTouchFeedback() {
FloatingViewManager manager = FloatingViewManager.getInstance();
if (manager != null) {
manager.flashTouchPoint();
}
}
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
}
@Override
public void onInterrupt() {
stopClicking();
logDebug("无障碍服务中断");
}
@Override
protected void onServiceConnected() {
super.onServiceConnected();
logDebug("无障碍服务已连接");
}
@Override
public void onDestroy() {
super.onDestroy();
stopClicking();
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,24 +1,38 @@
package com.auto.autoclicker;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.os.Build;
import android.provider.Settings;
import android.text.InputType;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Toast;
import com.auto.autoclicker.util.ScreenUtils;
import com.auto.autoclicker.util.ViewUtils;
public class FloatingViewManager {
private static final String TAG = "FloatingViewManager";
private static final long DEBOUNCE_INTERVAL = 500;
private static FloatingViewManager instance;
private final Context context;
private final WindowManager windowManager;
private View touchPointView;
@ -32,9 +46,11 @@ public class FloatingViewManager {
private long lastToggleTime = 0;
private final int screenWidth;
private final int screenHeight;
private final AutoClickService service = AutoClickService.getInstance();
public FloatingViewManager(Context context) {
this.context = context;
instance = this;
this.windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Point screenSize = ScreenUtils.getScreenSize(context);
this.screenWidth = screenSize.x;
@ -42,6 +58,10 @@ public class FloatingViewManager {
logDebug("屏幕尺寸: " + screenWidth + "x" + screenHeight);
}
public static FloatingViewManager getInstance() {
return instance;
}
public void showFloatingViews() throws SecurityException {
if (!Settings.canDrawOverlays(context)) {
throw new SecurityException("需要悬浮窗权限");
@ -61,6 +81,24 @@ public class FloatingViewManager {
logDebug("悬浮窗已添加");
}
public void removeFloatingViews() {
try {
if (touchPointView != null) {
windowManager.removeView(touchPointView);
touchPointView = null;
}
if (controlBarView != null) {
windowManager.removeView(controlBarView);
controlBarView = null;
}
isFloatingViewsShown = false;
logDebug("悬浮窗已移除");
} catch (Exception e) {
Log.e(TAG, "移除悬浮窗失败", e);
isFloatingViewsShown = false;
}
}
private void initializeTouchPointView() {
touchPointView = new View(context);
touchPointView.setBackgroundResource(R.drawable.un_touch_point);
@ -106,16 +144,7 @@ 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);
}
@SuppressLint("ClickableViewAccessibility")
private void initializeControlBarView() {
controlBarView = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.control_bar, null);
controlBarParams = new WindowManager.LayoutParams(
@ -150,18 +179,21 @@ public class FloatingViewManager {
float dy = event.getRawY() - lastY;
updateControlBarPosition(paramX, paramY, dx, dy);
return true;
case MotionEvent.ACTION_UP:
v.performClick();
return true;
}
return false;
}
});
Button toggleButton = controlBarView.findViewById(R.id.toggle_button);
toggleButton.setOnClickListener(v -> {
if (!isDebounced()) {
return;
}
ImageView play = controlBarView.findViewById(R.id.play_button);
ImageView close = controlBarView.findViewById(R.id.close_button);
ImageView setting = controlBarView.findViewById(R.id.settings_button);
play.setOnClickListener(v -> {
if (!isDebounced()) return;
AutoClickService service = AutoClickService.getInstance();
if (service == null) {
Log.e(TAG, "AutoClickService 未初始化");
Toast.makeText(context, "请在设置中启用无障碍服务", Toast.LENGTH_LONG).show();
@ -173,13 +205,13 @@ public class FloatingViewManager {
if (isClicking) {
service.stopClicking();
toggleButton.setText(R.string.start_click);
play.setBackgroundResource(R.drawable.play);
touchPointView.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();
toggleButton.setText(R.string.stop_click);
play.setBackgroundResource(R.drawable.play);
touchPointView.setBackgroundResource(R.drawable.touch_point);
Toast.makeText(context, "开始自动点击", Toast.LENGTH_SHORT).show();
}
@ -187,6 +219,25 @@ public class FloatingViewManager {
isClicking = !isClicking;
logDebug("服务是否点击中: " + service.isClicking());
});
close.setOnClickListener(v -> {
service.stopClicking();
touchPointView.setBackgroundResource(R.drawable.un_touch_point);
removeFloatingViews();
});
setting.setOnClickListener(v -> showInputDialog());
}
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 updateControlBarPosition(float paramX, float paramY, float dx, float dy) {
@ -197,6 +248,72 @@ public class FloatingViewManager {
windowManager.updateViewLayout(controlBarView, controlBarParams);
}
public void showInputDialog() {
EditText input = new EditText(context);
input.setInputType(InputType.TYPE_CLASS_NUMBER);
input.setHint("输入点击间隔ms");
input.setFocusableInTouchMode(true);
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("设置点击间隔")
.setView(input)
.setPositiveButton("确定", (dialog, which) -> {
String value = input.getText().toString();
try {
long interval = Long.parseLong(value);
AutoClickService service = AutoClickService.getInstance();
if (service != null) {
service.setClickInterval(interval);
} else {
Log.w("InputDialog", "AutoClickService 未初始化");
}
} catch (NumberFormatException e) {
Toast.makeText(context, "无效输入", Toast.LENGTH_SHORT).show();
}
dialog.dismiss();
})
.setNegativeButton("取消", (dialog, which) -> dialog.dismiss());
AlertDialog dialog = builder.create();
// 设置弹窗的类型允许在悬浮窗中显示输入框
if (!(context instanceof Activity)) {
if (dialog.getWindow() != null) {
dialog.getWindow().setType(
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ?
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY :
WindowManager.LayoutParams.TYPE_PHONE
);
}
}
dialog.show();
// 强制显示软键盘
input.requestFocus();
input.post(() -> {
InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
}
});
}
public void flashTouchPoint() {
if (touchPointView == null) return;
touchPointView.animate()
.alpha(0.3f)
.setDuration(100)
.withEndAction(() ->
touchPointView.animate()
.alpha(1.0f)
.setDuration(100)
.start()
)
.start();
}
private boolean isDebounced() {
long currentTime = System.currentTimeMillis();
if (currentTime - lastToggleTime < DEBOUNCE_INTERVAL) {
@ -206,25 +323,7 @@ public class FloatingViewManager {
return true;
}
public void removeFloatingViews() {
try {
if (touchPointView != null) {
windowManager.removeView(touchPointView);
touchPointView = null;
}
if (controlBarView != null) {
windowManager.removeView(controlBarView);
controlBarView = null;
}
isFloatingViewsShown = false;
logDebug("悬浮窗已移除");
} catch (Exception e) {
Log.e(TAG, "移除悬浮窗失败", e);
isFloatingViewsShown = false;
}
}
private void logDebug(String message) {
Log.d(TAG, message);
}
}
}

View File

@ -48,7 +48,6 @@ public class ForegroundService extends Service {
startForeground(NOTIFICATION_ID, notification);
// 仅在未显示悬浮窗时显示
if (floatingViewManager != null && !isFloatingViewShown) {
try {
floatingViewManager.showFloatingViews();
@ -65,10 +64,7 @@ public class ForegroundService extends Service {
return START_STICKY;
}
/**
* 创建通知渠道Android 8.0+
*/
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(

View File

@ -8,16 +8,17 @@ import android.os.Build;
import android.os.Bundle;
import android.os.PowerManager;
import android.provider.Settings;
import android.widget.Button;
import android.widget.Toast;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AppCompatActivity;
import com.auto.autoclicker.databinding.ActivityMainBinding;
public class MainActivity extends AppCompatActivity {
private Button startButton;
private ActivityMainBinding binding;
private ActivityResultLauncher<Intent> permissionLauncher;
private boolean isFloatingShown = false;
private long lastClickTime = 0;
@ -26,10 +27,11 @@ public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startButton = findViewById(R.id.start_Button);
startButton.setOnClickListener(v -> toggleFloatingWindow());
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
binding.startButton.setOnClickListener(v -> toggleFloatingWindow());
permissionLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> checkPermissions());
@ -75,7 +77,7 @@ public class MainActivity extends AppCompatActivity {
}
}
startButton.setEnabled(allPermissionsGranted);
binding.startButton.setEnabled(allPermissionsGranted);
updateButtonText();
}
@ -135,7 +137,9 @@ public class MainActivity extends AppCompatActivity {
isFloatingShown = true;
Toast.makeText(this, "悬浮窗已显示", Toast.LENGTH_SHORT).show();
} else {
AutoClickService service = AutoClickService.getInstance();
stopService(new Intent(this, ForegroundService.class));
service.stopClicking();
isFloatingShown = false;
Toast.makeText(this, "悬浮窗已隐藏", Toast.LENGTH_SHORT).show();
}
@ -143,6 +147,6 @@ public class MainActivity extends AppCompatActivity {
}
private void updateButtonText() {
startButton.setText(isFloatingShown ? R.string.hide_floating_window : R.string.show_floating_window);
binding.startButton.setText(isFloatingShown ? R.string.hide_floating_window : R.string.show_floating_window);
}
}

View File

@ -1,4 +1,4 @@
package com.auto.autoclicker;
package com.auto.autoclicker.util;
import android.content.Context;
import android.graphics.Point;

View File

@ -1,4 +1,4 @@
package com.auto.autoclicker;
package com.auto.autoclicker.util;
import android.graphics.Point;

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="M510.1,475.9L378.4,339.5c-10.4,-10.7 -27.4,-10.9 -38.1,-0.5 -5.2,4.9 -8.2,11.7 -8.3,18.9 -0.2,7.2 2.6,14.1 7.5,19.2l131.7,136.4 -136.4,131.7c-10.7,10.4 -10.9,27.4 -0.5,38.1 4.9,5.2 11.7,8.2 18.9,8.3 7.2,0.2 14.1,-2.6 19.2,-7.5l136.4,-131.7 131.7,136.4c10.4,10.7 27.4,10.9 38.1,0.5 5.2,-4.9 8.2,-11.7 8.3,-18.9 0.2,-7.2 -2.6,-14.1 -7.5,-19.2L547.7,514.8l136.4,-131.7c10.7,-10.4 10.9,-27.4 0.5,-38.1 -4.9,-5.2 -11.7,-8.2 -18.9,-8.3 -7.2,-0.2 -14.1,2.6 -19.2,7.5L510.1,475.9zM220.4,793.2c-155.7,-161.3 -151.2,-418.2 10,-574 161.3,-155.7 418.2,-151.2 574,10 155.7,161.3 151.3,418.2 -10,574 -161.3,155.7 -418.2,151.3 -574,-10zM220.4,793.2"
android:fillColor="#333333"/>
</vector>

View File

@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:fillColor="#FF000000"
android:pathData="M508,512m-112,0a112,112 0,1 0,224 0,112 112,0 1,0 -224,0Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M942.2,486.2C847.4,286.5 704.1,186 512,186c-192.2,0 -335.4,100.5 -430.2,300.3 -7.7,16.2 -7.7,35.2 0,51.5C176.6,737.5 319.9,838 512,838c192.2,0 335.4,-100.5 430.2,-300.3 7.7,-16.2 7.7,-35 0,-51.5zM508,688c-97.2,0 -176,-78.8 -176,-176s78.8,-176 176,-176 176,78.8 176,176 -78.8,176 -176,176z"/>
</vector>

View File

@ -0,0 +1,12 @@
<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="M512,74.7C270.9,74.7 74.7,270.9 74.7,512S270.9,949.3 512,949.3 949.3,753.1 949.3,512 753.1,74.7 512,74.7zM512,885.3c-204.8,0 -373.3,-168.5 -373.3,-373.3S307.2,138.7 512,138.7 885.3,307.2 885.3,512 716.8,885.3 512,885.3z"
android:fillColor="#666666"/>
<path
android:pathData="M708.3,465.1l-234.7,-134.4c-8.5,-4.3 -17.1,-6.4 -25.6,-6.4 -29.9,0 -53.3,23.5 -53.3,53.3v268.8c0,8.5 2.1,19.2 6.4,25.6 10.7,17.1 27.7,27.7 46.9,27.7 8.5,0 17.1,-2.1 25.6,-6.4l234.7,-134.4c8.5,-4.3 14.9,-10.7 19.2,-19.2 6.4,-12.8 8.5,-27.7 4.3,-40.5 -2.1,-14.9 -10.7,-25.6 -23.5,-34.1zM458.7,627.2L458.7,396.8L661.3,512l-202.7,115.2z"
android:fillColor="#666666"/>
</vector>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#80000000" /> <!-- 半透明黑色背景 -->
<corners android:radius="24dp" /> <!-- 圆角 -->
</shape>

View File

@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:fillColor="#FF000000"
android:pathData="M819.8,83.7L207,83.7c-67.7,0 -122.6,54.9 -122.6,122.6v612.8c0,67.7 54.9,122.6 122.6,122.6h612.8c67.7,0 122.6,-54.9 122.6,-122.6L942.4,206.3c-0,-67.7 -54.9,-122.6 -122.6,-122.6zM695.4,147v241.1L331.8,388.1L331.8,147h363.6zM881.2,819.3c0,33.8 -27.3,61.2 -61.1,61.2L207.1,880.5c-16.4,0 -31.9,-6.3 -43.5,-17.9s-18,-26.9 -18,-43.3v-612.9c0.1,-33.9 27.6,-61.4 61.5,-61.4h61.3v245.3c-0.1,33.8 27.3,61.2 61.1,61.2h367.9c33.9,0 61.3,-27.4 61.3,-61.2L758.7,144.9h61.2c33.9,0 61.3,27.5 61.3,61.4L881.2,819.3z"/>
<path
android:fillColor="#FF000000"
android:pathData="M574.8,329.9c17.5,0 31.7,-14.2 31.7,-31.7v-61.3c0,-17.5 -14.2,-31.7 -31.7,-31.7s-31.7,14.2 -31.7,31.7v61.3c0,17.5 14.2,31.7 31.7,31.7z"/>
</vector>

View File

@ -0,0 +1,12 @@
<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="M509.4,666.1c-83.6,0 -151.5,-67.9 -151.5,-151.5s67.9,-151.5 151.5,-151.5 151.5,67.9 151.5,151.5 -67.9,151.5 -151.5,151.5zM509.4,404.9c-60.6,0 -109.7,49.1 -109.7,109.7s49.1,109.7 109.7,109.7 109.7,-49.1 109.7,-109.7 -49.1,-109.7 -109.7,-109.7z"
android:fillColor="#333333"/>
<path
android:pathData="M556.4,930h-83.6c-47.5,0 -86.2,-38.7 -86.2,-86.2v-23c0,-1 -0.5,-2.1 -1.6,-2.6h-0.5c-1,-0.5 -2.1,0 -3.1,0.5l-14.6,15.2c-16.2,16.2 -37.1,25.1 -59.6,25.1 -22.5,0 -43.4,-8.9 -59,-24.6l-59,-59c-32.4,-32.4 -32.4,-85.2 0,-118.1l15.7,-15.2c1,-1 1,-2.1 0.5,-3.1v-0.5c-0.5,-1 -1.6,-1.6 -2.6,-1.6h-23c-47.5,0 -86.2,-38.7 -86.2,-86.2v-78.4c0.5,-47 39.2,-85.7 86.7,-85.7h21.4c1,0 2.1,-0.5 2.6,-2.1 0.5,-1 1,-2.6 1.6,-3.7 0.5,-1 0,-2.1 -0.5,-3.1l-16.2,-16.7C156.7,329.1 156.7,275.9 189.1,243.5l59,-59c15.7,-15.7 36.6,-24.6 59,-24.6 22.5,0 43.4,8.9 59,24.6l15.2,15.7c0.5,1 2.1,1 3.1,0.5h0.5c1,-0.5 1.6,-1.6 1.6,-2.6v-17.8C386.6,132.7 425.3,94 472.8,94h83.6c44.4,0 81,36.6 81,81v21.4c0,1 0.5,2.1 2.1,2.6 1.6,0.5 2.6,1 3.7,1.6 1,0.5 2.1,0 3.1,-0.5l16.7,-16.2c32.4,-32.4 85.2,-32.4 118.1,0.5l59,59c15.7,15.7 24.6,36.6 24.6,59 0,22.5 -8.9,43.4 -24.6,59l-15.7,16.2c-0.5,0.5 -1,2.1 -0.5,2.6 0.5,1 1,2.6 1.6,3.7 0.5,1 1.6,2.1 2.6,2.1h21.4c44.4,0 81,36.6 81,81v88.8c0,44.4 -36.6,81 -81,81h-23c-1,0 -2.1,0.5 -2.6,1.6 -0.5,1.6 -0.5,2.6 0.5,3.7l15.2,14.6c16.2,16.2 25.1,37.1 24.6,59.6 0,22.5 -8.9,43.4 -24.6,59l-59,59c-15.7,15.7 -36.6,24.6 -59,24.6s-43.4,-8.9 -59,-24.6l-16.2,-15.7c-0.5,-0.5 -2.1,-1 -2.6,-0.5 -1,0.5 -2.6,1 -3.7,1.6 -1,0.5 -2.1,1.6 -2.1,2.6v26.6C637.4,893.4 600.8,930 556.4,930zM402.3,780.5c16.2,7.3 26.1,23 26.1,40.8v23c0,24.6 19.9,44.4 44.4,44.4h83.6c21.4,0 39.2,-17.8 39.2,-39.2v-26.6c0,-18.3 11,-34.5 28.2,-41.3 1,-0.5 1.6,-0.5 2.6,-1 16.7,-7.3 35.5,-3.7 48.6,8.9l16.2,15.7c16.7,16.7 43.4,16.7 59.6,0l59,-59c7.8,-7.8 12,-18.3 12,-29.8 0,-11 -4.2,-21.4 -12,-29.8l-14.6,-14.1c-13.6,-13.1 -17.8,-32.9 -9.9,-50.2v-0.5c6.8,-15.7 23,-26.1 40.8,-26.1h23c21.4,0 39.2,-17.8 39.2,-39.2v-88.8c0,-21.4 -17.8,-39.2 -39.2,-39.2h-21.4c-18.3,0 -34.5,-11 -41.3,-28.2 -0.5,-1 -0.5,-1.6 -1,-2.6 -7.3,-16.7 -3.7,-35.5 8.9,-48.6l15.7,-16.2c7.8,-7.8 12.5,-18.8 12.5,-29.8 0,-11.5 -4.2,-21.9 -12,-29.8L751.3,214.2c-16.2,-16.2 -42.8,-16.2 -59,0l-17.2,16.2c-13.1,12.5 -32.4,15.7 -48.6,8.9 -0.5,-0.5 -1.6,-0.5 -2.6,-1 -17.2,-6.8 -28.2,-23 -28.2,-41.3v-21.4c0,-21.4 -17.8,-39.2 -39.2,-39.2h-83.6c-24.6,0 -44.4,19.9 -44.4,44.4V198.5c0,17.8 -10.4,33.4 -26.6,40.8 -17.2,7.8 -37.1,3.7 -50.2,-9.4l-15.2,-15.7c-7.8,-7.8 -18.3,-12 -29.3,-12 -11,0 -21.4,4.2 -29.3,12L218.9,272.7c-16.2,16.2 -16.2,42.8 0,59l16.2,17.2c12.5,13.1 16.2,32.4 8.9,48.6 -0.5,0.5 -0.5,1.6 -1,2.6 -6.8,17.2 -23,28.2 -41.3,28.2h-21.4c-24.6,0 -44.4,19.9 -44.4,44.4v78.4c0,24.6 19.9,44.4 44.4,44.4h23c17.8,0 33.4,10.4 40.8,26.6v0.5c7.3,16.7 3.7,37.1 -9.4,49.6l-15.7,15.2c-16.2,16.2 -16.2,42.3 0,58.5l59,59c7.8,7.8 18.3,12 29.3,12 11,0 21.4,-4.2 29.8,-12.5l14.1,-14.6c13.1,-13.6 32.9,-17.8 50.2,-9.9l1,0.5z"
android:fillColor="#333333"/>
</vector>

View File

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

View File

@ -6,4 +6,10 @@
<string name="hide_floating_window">隐藏悬浮窗</string>
<string name="start_click">开始点击</string>
<string name="stop_click">停止点击</string>
<string name="play_button_desc">Play</string>
<string name="file_button_desc">File</string>
<string name="camera_button_desc">Camera</string>
<string name="eye_button_desc">Eye</string>
<string name="settings_button_desc">Settings</string>
<string name="close_button_desc">Close</string>
</resources>