初步多点实现
This commit is contained in:
parent
84e4871838
commit
3f6fb462ee
@ -27,7 +27,6 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- 无障碍服务 -->
|
||||
<service
|
||||
android:name=".AutoClickService"
|
||||
android:enabled="true"
|
||||
@ -41,7 +40,6 @@
|
||||
android:resource="@xml/accessibility_service_config" />
|
||||
</service>
|
||||
|
||||
<!-- 前台服务 -->
|
||||
<service
|
||||
android:name=".ForegroundService"
|
||||
android:enabled="true"
|
||||
|
||||
@ -15,10 +15,18 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
import com.auto.autoclicker.util.ScreenUtils;
|
||||
import com.auto.autoclicker.util.ViewUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class AutoClickService extends AccessibilityService {
|
||||
private final List<Point> multiClickPoints = new ArrayList<>();
|
||||
|
||||
private static final String TAG = "AutoClickService";
|
||||
private static AutoClickService instance;
|
||||
|
||||
private final List<Point> multiClickPositions = new ArrayList<>();
|
||||
private int currentClickIndex = 0;
|
||||
|
||||
private static final long MIN_CLICK_INTERVAL = 40;
|
||||
private static final long MAX_CLICK_INTERVAL = 10000;
|
||||
private static final int MIN_CLICK_DURATION = 50;
|
||||
@ -44,6 +52,10 @@ public class AutoClickService extends AccessibilityService {
|
||||
logDebug("屏幕尺寸: " + screenWidth + "x" + screenHeight);
|
||||
}
|
||||
|
||||
public static AutoClickService getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceConnected() {
|
||||
super.onServiceConnected();
|
||||
@ -56,25 +68,17 @@ public class AutoClickService extends AccessibilityService {
|
||||
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 instance;
|
||||
}
|
||||
|
||||
public void setClickPosition(float x, float y) {
|
||||
Point constrained = ViewUtils.constrainToScreen(x, y, screenWidth, screenHeight);
|
||||
this.clickX = constrained.x;
|
||||
this.clickY = constrained.y;
|
||||
logDebug("设置点击位置: 原始 (" + x + ", " + y + ") -> 修正 (" + clickX + ", " + clickY + ")");
|
||||
logDebug("设置单点点击位置: 原始 (" + x + ", " + y + ") -> 修正 (" + clickX + ", " + clickY + ")");
|
||||
}
|
||||
|
||||
public void setMultiClickPositions(List<Point> positions) {
|
||||
this.multiClickPositions.clear();
|
||||
this.multiClickPositions.addAll(positions);
|
||||
logDebug("设置多点点击位置: " + positions.size() + " 个点");
|
||||
}
|
||||
|
||||
public void setClickInterval(long interval) {
|
||||
@ -97,7 +101,12 @@ public class AutoClickService extends AccessibilityService {
|
||||
|
||||
public void startClicking() {
|
||||
if (!isClicking) {
|
||||
if (multiClickPositions.isEmpty() && (clickX == 0 && clickY == 0)) {
|
||||
Log.w(TAG, "无有效点击位置,忽略开始点击");
|
||||
return;
|
||||
}
|
||||
isClicking = true;
|
||||
currentClickIndex = 0;
|
||||
logDebug("开始自动点击");
|
||||
performClick();
|
||||
}
|
||||
@ -121,11 +130,22 @@ public class AutoClickService extends AccessibilityService {
|
||||
return;
|
||||
}
|
||||
|
||||
logDebug("执行点击: (" + clickX + ", " + clickY + ")");
|
||||
// 决定使用单点还是多点点击
|
||||
Point clickPoint;
|
||||
if (!multiClickPositions.isEmpty()) {
|
||||
// 多点点击模式
|
||||
clickPoint = multiClickPositions.get(currentClickIndex);
|
||||
currentClickIndex = (currentClickIndex + 1) % multiClickPositions.size();
|
||||
} else {
|
||||
// 单点点击模式
|
||||
clickPoint = new Point(clickX, clickY);
|
||||
}
|
||||
|
||||
logDebug("执行点击: (" + clickPoint.x + ", " + clickPoint.y + ")");
|
||||
flashTouchFeedback();
|
||||
|
||||
Path path = new Path();
|
||||
path.moveTo(clickX, clickY);
|
||||
path.moveTo(clickPoint.x, clickPoint.y);
|
||||
GestureDescription.StrokeDescription stroke =
|
||||
new GestureDescription.StrokeDescription(path, 0, clickDuration);
|
||||
GestureDescription gesture =
|
||||
@ -162,4 +182,14 @@ public class AutoClickService extends AccessibilityService {
|
||||
private void logDebug(String message) {
|
||||
Log.d(TAG, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
instance = null;
|
||||
stopClicking();
|
||||
Intent intent = new Intent("com.auto.autoclicker.SERVICE_DESTROYED");
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
|
||||
logDebug("无障碍服务已销毁");
|
||||
}
|
||||
}
|
||||
@ -2,7 +2,6 @@ package com.auto.autoclicker;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@ -24,27 +23,45 @@ import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
|
||||
import com.auto.autoclicker.util.PrefUtils;
|
||||
import com.auto.autoclicker.util.ScreenUtils;
|
||||
import com.auto.autoclicker.util.ViewUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class FloatingViewManager {
|
||||
private static final String TAG = "FloatingViewManager";
|
||||
private static final long DEBOUNCE_INTERVAL = 500;
|
||||
|
||||
private final Context context;
|
||||
|
||||
private static final long DEBOUNCE_INTERVAL = 500;
|
||||
|
||||
private final WindowManager windowManager;
|
||||
private View touchPointView;
|
||||
private LinearLayout controlBarView;
|
||||
private WindowManager.LayoutParams touchPointParams;
|
||||
private WindowManager.LayoutParams controlBarParams;
|
||||
|
||||
private final List<View> moreTouchPointViews = new ArrayList<>();
|
||||
private final List<WindowManager.LayoutParams> moreTouchPointParams = new ArrayList<>();
|
||||
|
||||
private View singleTouchPointView;
|
||||
private WindowManager.LayoutParams singleTouchPointParams;
|
||||
|
||||
private LinearLayout singleControlBarView;
|
||||
private LinearLayout moreControlBarView;
|
||||
|
||||
private WindowManager.LayoutParams singleControlBarParams;
|
||||
private WindowManager.LayoutParams moreControlBarParams;
|
||||
|
||||
private float touchPointX = 500;
|
||||
private float touchPointY = 500;
|
||||
|
||||
private boolean isClicking = false;
|
||||
private boolean isFloatingViewsShown = false;
|
||||
|
||||
private long lastToggleTime = 0;
|
||||
|
||||
private final int screenWidth;
|
||||
private final int screenHeight;
|
||||
|
||||
@ -58,47 +75,61 @@ public class FloatingViewManager {
|
||||
logDebug("屏幕尺寸: " + screenWidth + "x" + screenHeight);
|
||||
}
|
||||
|
||||
public void showFloatingViews() throws SecurityException {
|
||||
private void registerBroadcast(Context context) {
|
||||
LocalBroadcastManager.getInstance(context).registerReceiver(new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if ("com.auto.autoclicker.FLASH_TOUCH_POINT".equals(intent.getAction())) {
|
||||
flashTouchPoint();
|
||||
}
|
||||
}
|
||||
}, new IntentFilter("com.auto.autoclicker.FLASH_TOUCH_POINT"));
|
||||
}
|
||||
|
||||
public void showFloatingViews(int mode) throws SecurityException {
|
||||
if (!Settings.canDrawOverlays(context)) {
|
||||
throw new SecurityException("需要悬浮窗权限");
|
||||
}
|
||||
|
||||
if (isFloatingViewsShown) {
|
||||
logDebug("悬浮窗已存在,清理后重新创建");
|
||||
removeFloatingViews();
|
||||
removeFloatingViews();
|
||||
|
||||
if (mode == 1) {
|
||||
initSingleTouchPointView();
|
||||
initSingleControlBar();
|
||||
|
||||
if (singleTouchPointView != null) {
|
||||
windowManager.addView(singleTouchPointView, singleTouchPointParams);
|
||||
}
|
||||
|
||||
if (singleControlBarView != null) {
|
||||
windowManager.addView(singleControlBarView, singleControlBarParams);
|
||||
}
|
||||
} else if (mode == 2) {
|
||||
initMoreTouchPointView();
|
||||
initMoreControlBar();
|
||||
|
||||
if (moreTouchPointViews.size() == moreTouchPointParams.size()) {
|
||||
for (int i = 0; i < moreTouchPointViews.size(); i++) {
|
||||
windowManager.addView(moreTouchPointViews.get(i), moreTouchPointParams.get(i));
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "触摸点与布局参数数量不一致");
|
||||
}
|
||||
|
||||
|
||||
if (moreControlBarView != null) {
|
||||
windowManager.addView(moreControlBarView, moreControlBarParams);
|
||||
}
|
||||
}
|
||||
|
||||
initializeTouchPointView();
|
||||
initializeControlBarView();
|
||||
|
||||
windowManager.addView(touchPointView, touchPointParams);
|
||||
windowManager.addView(controlBarView, controlBarParams);
|
||||
isFloatingViewsShown = true;
|
||||
logDebug("悬浮窗已添加");
|
||||
logDebug("悬浮窗已添加,模式 = " + mode);
|
||||
}
|
||||
|
||||
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);
|
||||
touchPointParams = new WindowManager.LayoutParams(
|
||||
private void initSingleTouchPointView() {
|
||||
singleTouchPointView = new View(context);
|
||||
singleTouchPointView.setBackgroundResource(R.drawable.un_touch_point);
|
||||
singleTouchPointParams = new WindowManager.LayoutParams(
|
||||
100, 100,
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ?
|
||||
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY :
|
||||
@ -107,11 +138,11 @@ public class FloatingViewManager {
|
||||
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
|
||||
PixelFormat.TRANSLUCENT
|
||||
);
|
||||
touchPointParams.gravity = Gravity.TOP | Gravity.START;
|
||||
touchPointParams.x = (int) touchPointX;
|
||||
touchPointParams.y = (int) touchPointY;
|
||||
singleTouchPointParams.gravity = Gravity.TOP | Gravity.START;
|
||||
singleTouchPointParams.x = (int) touchPointX;
|
||||
singleTouchPointParams.y = (int) touchPointY;
|
||||
|
||||
touchPointView.setOnTouchListener(new View.OnTouchListener() {
|
||||
singleTouchPointView.setOnTouchListener(new View.OnTouchListener() {
|
||||
private float lastX, lastY;
|
||||
private float paramX, paramY;
|
||||
|
||||
@ -121,8 +152,8 @@ public class FloatingViewManager {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
lastX = event.getRawX();
|
||||
lastY = event.getRawY();
|
||||
paramX = touchPointParams.x;
|
||||
paramY = touchPointParams.y;
|
||||
paramX = singleTouchPointParams.x;
|
||||
paramY = singleTouchPointParams.y;
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
float dx = event.getRawX() - lastX;
|
||||
@ -131,7 +162,7 @@ public class FloatingViewManager {
|
||||
AutoClickService service = AutoClickService.getInstance();
|
||||
if (service != null) {
|
||||
service.setClickPosition(touchPointX + 50, touchPointY + 50);
|
||||
logDebug("触摸点移动到: (" + touchPointX + ", " + touchPointY + ")");
|
||||
logDebug("单点触摸点移动到: (" + touchPointX + ", " + touchPointY + ")");
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -140,10 +171,16 @@ public class FloatingViewManager {
|
||||
});
|
||||
}
|
||||
|
||||
private void initMoreTouchPointView() {
|
||||
moreTouchPointViews.clear();
|
||||
moreTouchPointParams.clear();
|
||||
addNewTouchPoint(100, 500);
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
private void initializeControlBarView() {
|
||||
controlBarView = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.single_control_bar, null);
|
||||
controlBarParams = new WindowManager.LayoutParams(
|
||||
private void initSingleControlBar() {
|
||||
singleControlBarView = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.single_control_bar, null);
|
||||
singleControlBarParams = new WindowManager.LayoutParams(
|
||||
WindowManager.LayoutParams.WRAP_CONTENT,
|
||||
WindowManager.LayoutParams.WRAP_CONTENT,
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ?
|
||||
@ -153,11 +190,11 @@ public class FloatingViewManager {
|
||||
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
|
||||
PixelFormat.TRANSLUCENT
|
||||
);
|
||||
controlBarParams.gravity = Gravity.TOP | Gravity.START;
|
||||
controlBarParams.x = 0;
|
||||
controlBarParams.y = 200;
|
||||
singleControlBarParams.gravity = Gravity.TOP | Gravity.START;
|
||||
singleControlBarParams.x = 0;
|
||||
singleControlBarParams.y = 200;
|
||||
|
||||
controlBarView.setOnTouchListener(new View.OnTouchListener() {
|
||||
singleControlBarView.setOnTouchListener(new View.OnTouchListener() {
|
||||
private float lastX, lastY;
|
||||
private float paramX, paramY;
|
||||
|
||||
@ -167,13 +204,13 @@ public class FloatingViewManager {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
lastX = event.getRawX();
|
||||
lastY = event.getRawY();
|
||||
paramX = controlBarParams.x;
|
||||
paramY = controlBarParams.y;
|
||||
paramX = singleControlBarParams.x;
|
||||
paramY = singleControlBarParams.y;
|
||||
return true;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
float dx = event.getRawX() - lastX;
|
||||
float dy = event.getRawY() - lastY;
|
||||
updateControlBarPosition(paramX, paramY, dx, dy);
|
||||
updateSingleControlBarPosition(paramX, paramY, dx, dy);
|
||||
return true;
|
||||
case MotionEvent.ACTION_UP:
|
||||
v.performClick();
|
||||
@ -183,84 +220,304 @@ public class FloatingViewManager {
|
||||
}
|
||||
});
|
||||
|
||||
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();
|
||||
Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
context.startActivity(intent);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isClicking) {
|
||||
service.stopClicking();
|
||||
play.setBackgroundResource(R.drawable.play);
|
||||
touchPointView.setBackgroundResource(R.drawable.un_touch_point);
|
||||
Toast.makeText(context, "停止自动点击", Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
service.setClickPosition(touchPointX, touchPointY);
|
||||
service.startClicking();
|
||||
play.setBackgroundResource(R.drawable.play);
|
||||
touchPointView.setBackgroundResource(R.drawable.touch_point);
|
||||
Toast.makeText(context, "开始自动点击", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
isClicking = !isClicking;
|
||||
logDebug("服务是否点击中: " + service.isClicking());
|
||||
});
|
||||
|
||||
close.setOnClickListener(v -> {
|
||||
AutoClickService service = AutoClickService.getInstance();
|
||||
|
||||
if (service != null) {
|
||||
service.stopClicking();
|
||||
} else {
|
||||
logDebug("AutoClickService 未初始化");
|
||||
Toast.makeText(context, "请启用无障碍服务", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
touchPointView.setBackgroundResource(R.drawable.un_touch_point);
|
||||
removeFloatingViews();
|
||||
|
||||
context.stopService(new Intent(context, ForegroundService.class));
|
||||
|
||||
PrefUtils.setFloatingShown(context, false);
|
||||
|
||||
Intent intent = new Intent("com.auto.autoclicker.FLOATING_WINDOW_STATE_CHANGED");
|
||||
intent.putExtra("isShown", false);
|
||||
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
|
||||
|
||||
});
|
||||
ImageView play = singleControlBarView.findViewById(R.id.play_button);
|
||||
ImageView close = singleControlBarView.findViewById(R.id.close_button);
|
||||
ImageView setting = singleControlBarView.findViewById(R.id.settings_button);
|
||||
|
||||
play.setOnClickListener(v -> toggleSingleClicking(play));
|
||||
close.setOnClickListener(v -> closeFloatingViews());
|
||||
setting.setOnClickListener(v -> showInputDialog());
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
private void initMoreControlBar() {
|
||||
moreControlBarView = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.more_control_bar, null);
|
||||
moreControlBarParams = new WindowManager.LayoutParams(
|
||||
WindowManager.LayoutParams.WRAP_CONTENT,
|
||||
WindowManager.LayoutParams.WRAP_CONTENT,
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ?
|
||||
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY :
|
||||
WindowManager.LayoutParams.TYPE_PHONE,
|
||||
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
|
||||
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
|
||||
PixelFormat.TRANSLUCENT
|
||||
);
|
||||
moreControlBarParams.gravity = Gravity.TOP | Gravity.START;
|
||||
moreControlBarParams.x = 0;
|
||||
moreControlBarParams.y = 200;
|
||||
|
||||
moreControlBarView.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 = moreControlBarParams.x;
|
||||
paramY = moreControlBarParams.y;
|
||||
return true;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
float dx = event.getRawX() - lastX;
|
||||
float dy = event.getRawY() - lastY;
|
||||
updateMoreControlBarPosition(paramX, paramY, dx, dy);
|
||||
return true;
|
||||
case MotionEvent.ACTION_UP:
|
||||
v.performClick();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
ImageView addButton = moreControlBarView.findViewById(R.id.add_button);
|
||||
ImageView removeButton = moreControlBarView.findViewById(R.id.remove_button);
|
||||
ImageView playButton = moreControlBarView.findViewById(R.id.play_button);
|
||||
ImageView closeButton = moreControlBarView.findViewById(R.id.close_button);
|
||||
ImageView settingButton = moreControlBarView.findViewById(R.id.settings_button);
|
||||
|
||||
addButton.setOnClickListener(v -> addNewTouchPoint(100 + moreTouchPointViews.size() * 120, 500));
|
||||
removeButton.setOnClickListener(v -> removeLastTouchPoint());
|
||||
playButton.setOnClickListener(v -> toggleMoreClicking(playButton));
|
||||
closeButton.setOnClickListener(v -> closeFloatingViews());
|
||||
settingButton.setOnClickListener(v -> showInputDialog());
|
||||
}
|
||||
|
||||
private void toggleSingleClicking(ImageView play) {
|
||||
if (isDebounced()) return;
|
||||
|
||||
AutoClickService service = AutoClickService.getInstance();
|
||||
if (service == null) {
|
||||
Log.e(TAG, "AutoClickService 未初始化");
|
||||
Toast.makeText(context, "请在设置中启用无障碍服务", Toast.LENGTH_LONG).show();
|
||||
Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
context.startActivity(intent);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isClicking) {
|
||||
service.stopClicking();
|
||||
play.setBackgroundResource(R.drawable.play);
|
||||
singleTouchPointView.setBackgroundResource(R.drawable.un_touch_point);
|
||||
Toast.makeText(context, "停止自动点击", Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
service.setClickPosition(touchPointX + 50, touchPointY + 50);
|
||||
service.startClicking();
|
||||
play.setBackgroundResource(R.drawable.pause);
|
||||
singleTouchPointView.setBackgroundResource(R.drawable.touch_point);
|
||||
Toast.makeText(context, "开始自动点击", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
isClicking = !isClicking;
|
||||
logDebug("单点服务是否点击中: " + service.isClicking());
|
||||
}
|
||||
|
||||
private void toggleMoreClicking(ImageView play) {
|
||||
if (isDebounced()) return;
|
||||
|
||||
AutoClickService service = AutoClickService.getInstance();
|
||||
if (service == null) {
|
||||
Log.e(TAG, "AutoClickService 未初始化");
|
||||
Toast.makeText(context, "请在设置中启用无障碍服务", Toast.LENGTH_LONG).show();
|
||||
Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
context.startActivity(intent);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isClicking) {
|
||||
service.stopClicking();
|
||||
play.setBackgroundResource(R.drawable.play);
|
||||
for (View point : moreTouchPointViews) {
|
||||
point.setBackgroundResource(R.drawable.un_touch_point);
|
||||
}
|
||||
Toast.makeText(context, "停止多点自动点击", Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
List<Point> positions = new ArrayList<>();
|
||||
for (WindowManager.LayoutParams params : moreTouchPointParams) {
|
||||
positions.add(new Point(params.x + 50, params.y + 50));
|
||||
}
|
||||
service.setMultiClickPositions(positions);
|
||||
service.startClicking();
|
||||
play.setBackgroundResource(R.drawable.pause);
|
||||
for (View point : moreTouchPointViews) {
|
||||
point.setBackgroundResource(R.drawable.touch_point);
|
||||
}
|
||||
Toast.makeText(context, "开始多点自动点击", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
isClicking = !isClicking;
|
||||
logDebug("多点服务是否点击中: " + service.isClicking());
|
||||
}
|
||||
|
||||
private void closeFloatingViews() {
|
||||
AutoClickService service = AutoClickService.getInstance();
|
||||
if (service != null) {
|
||||
service.stopClicking();
|
||||
} else {
|
||||
logDebug("AutoClickService 未初始化");
|
||||
Toast.makeText(context, "请启用无障碍服务", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
if (singleTouchPointView != null) {
|
||||
singleTouchPointView.setBackgroundResource(R.drawable.un_touch_point);
|
||||
}
|
||||
for (View point : moreTouchPointViews) {
|
||||
point.setBackgroundResource(R.drawable.un_touch_point);
|
||||
}
|
||||
|
||||
removeFloatingViews();
|
||||
|
||||
context.stopService(new Intent(context, ForegroundService.class));
|
||||
PrefUtils.setFloatingShown(context, 0);
|
||||
|
||||
Intent intent = new Intent("com.auto.autoclicker.FLOATING_WINDOW_STATE_CHANGED");
|
||||
intent.putExtra("isShown", false);
|
||||
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
|
||||
}
|
||||
|
||||
public void removeFloatingViews() {
|
||||
try {
|
||||
// 移除单点触摸视图
|
||||
if (singleTouchPointView != null) {
|
||||
try {
|
||||
windowManager.removeView(singleTouchPointView);
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, "移除 singleTouchPointView 失败", e);
|
||||
}
|
||||
singleTouchPointView = null;
|
||||
}
|
||||
|
||||
// 移除多点触摸视图
|
||||
List<View> pointsToRemove = new ArrayList<>(moreTouchPointViews);
|
||||
for (View point : pointsToRemove) {
|
||||
try {
|
||||
windowManager.removeView(point);
|
||||
moreTouchPointViews.remove(point); // 成功移除后从列表中删除
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, "移除 multiTouchPoint 失败", e);
|
||||
}
|
||||
}
|
||||
moreTouchPointParams.clear(); // 清空参数列表
|
||||
|
||||
// 移除单点控制栏
|
||||
if (singleControlBarView != null) {
|
||||
try {
|
||||
windowManager.removeView(singleControlBarView);
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, "移除 singleControlBarView 失败", e);
|
||||
}
|
||||
singleControlBarView = null;
|
||||
}
|
||||
|
||||
// 移除多点控制栏
|
||||
if (moreControlBarView != null) {
|
||||
try {
|
||||
windowManager.removeView(moreControlBarView);
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, "移除 moreControlBarView 失败", e);
|
||||
}
|
||||
moreControlBarView = null;
|
||||
}
|
||||
|
||||
isFloatingViewsShown = false;
|
||||
isClicking = false;
|
||||
logDebug("悬浮窗已移除");
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "移除悬浮窗失败", e);
|
||||
isFloatingViewsShown = false;
|
||||
isClicking = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void addNewTouchPoint(int x, int y) {
|
||||
View point = new View(context);
|
||||
point.setBackgroundResource(R.drawable.un_touch_point);
|
||||
WindowManager.LayoutParams params = createTouchPointLayoutParams(x, y);
|
||||
windowManager.addView(point, params);
|
||||
moreTouchPointViews.add(point);
|
||||
moreTouchPointParams.add(params);
|
||||
|
||||
point.setOnTouchListener(new View.OnTouchListener() {
|
||||
private float lastX, lastY, startX, startY;
|
||||
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
lastX = event.getRawX();
|
||||
lastY = event.getRawY();
|
||||
startX = params.x;
|
||||
startY = params.y;
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
float dx = event.getRawX() - lastX;
|
||||
float dy = event.getRawY() - lastY;
|
||||
params.x = (int) (startX + dx);
|
||||
params.y = (int) (startY + dy);
|
||||
windowManager.updateViewLayout(v, params);
|
||||
logDebug("多点触摸点移动到: (" + params.x + ", " + params.y + ")");
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void removeLastTouchPoint() {
|
||||
if (moreTouchPointViews.size() <= 1) {
|
||||
Toast.makeText(context, "至少保留一个触摸点", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
int lastIndex = moreTouchPointViews.size() - 1;
|
||||
View last = moreTouchPointViews.remove(lastIndex);
|
||||
moreTouchPointParams.remove(lastIndex);
|
||||
windowManager.removeView(last);
|
||||
}
|
||||
|
||||
private WindowManager.LayoutParams createTouchPointLayoutParams(int x, int y) {
|
||||
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
|
||||
100, 100,
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ?
|
||||
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY :
|
||||
WindowManager.LayoutParams.TYPE_PHONE,
|
||||
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
|
||||
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
|
||||
PixelFormat.TRANSLUCENT
|
||||
);
|
||||
params.gravity = Gravity.TOP | Gravity.START;
|
||||
params.x = x;
|
||||
params.y = y;
|
||||
return params;
|
||||
}
|
||||
|
||||
private void updateTouchPointPosition(float paramX, float paramY, float dx, float dy) {
|
||||
Point constrainedPoint = ViewUtils.constrainToScreen(
|
||||
paramX + dx, paramY + dy, screenWidth - touchPointView.getWidth(), screenHeight - touchPointView.getHeight());
|
||||
touchPointParams.x = constrainedPoint.x;
|
||||
touchPointParams.y = constrainedPoint.y;
|
||||
touchPointX = touchPointParams.x;
|
||||
touchPointY = touchPointParams.y;
|
||||
windowManager.updateViewLayout(touchPointView, touchPointParams);
|
||||
paramX + dx, paramY + dy, screenWidth - singleTouchPointView.getWidth(), screenHeight - singleTouchPointView.getHeight());
|
||||
singleTouchPointParams.x = constrainedPoint.x;
|
||||
singleTouchPointParams.y = constrainedPoint.y;
|
||||
touchPointX = singleTouchPointParams.x;
|
||||
touchPointY = singleTouchPointParams.y;
|
||||
windowManager.updateViewLayout(singleTouchPointView, singleTouchPointParams);
|
||||
}
|
||||
|
||||
private void updateControlBarPosition(float paramX, float paramY, float dx, float dy) {
|
||||
private void updateSingleControlBarPosition(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);
|
||||
paramX + dx, paramY + dy, screenWidth - singleControlBarView.getWidth(), screenHeight - singleControlBarView.getHeight());
|
||||
singleControlBarParams.x = constrainedPoint.x;
|
||||
singleControlBarParams.y = constrainedPoint.y;
|
||||
windowManager.updateViewLayout(singleControlBarView, singleControlBarParams);
|
||||
}
|
||||
|
||||
private void updateMoreControlBarPosition(float paramX, float paramY, float dx, float dy) {
|
||||
Point constrainedPoint = ViewUtils.constrainToScreen(
|
||||
paramX + dx, paramY + dy, screenWidth - moreControlBarView.getWidth(), screenHeight - moreControlBarView.getHeight());
|
||||
moreControlBarParams.x = constrainedPoint.x;
|
||||
moreControlBarParams.y = constrainedPoint.y;
|
||||
windowManager.updateViewLayout(moreControlBarView, moreControlBarParams);
|
||||
}
|
||||
|
||||
public void showInputDialog() {
|
||||
@ -303,7 +560,6 @@ public class FloatingViewManager {
|
||||
|
||||
dialog.show();
|
||||
|
||||
// 强制显示软键盘
|
||||
input.requestFocus();
|
||||
input.post(() -> {
|
||||
InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
@ -314,41 +570,42 @@ public class FloatingViewManager {
|
||||
}
|
||||
|
||||
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 void registerBroadcast(Context context) {
|
||||
LocalBroadcastManager.getInstance(context).registerReceiver(new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if ("com.auto.autoclicker.FLASH_TOUCH_POINT".equals(intent.getAction())) {
|
||||
flashTouchPoint();
|
||||
}
|
||||
}
|
||||
}, new IntentFilter("com.auto.autoclicker.FLASH_TOUCH_POINT"));
|
||||
if (singleTouchPointView != null) {
|
||||
singleTouchPointView.animate()
|
||||
.alpha(0.3f)
|
||||
.setDuration(100)
|
||||
.withEndAction(() ->
|
||||
singleTouchPointView.animate()
|
||||
.alpha(1.0f)
|
||||
.setDuration(100)
|
||||
.start()
|
||||
)
|
||||
.start();
|
||||
}
|
||||
for (View point : moreTouchPointViews) {
|
||||
point.animate()
|
||||
.alpha(0.3f)
|
||||
.setDuration(100)
|
||||
.withEndAction(() ->
|
||||
point.animate()
|
||||
.alpha(1.0f)
|
||||
.setDuration(100)
|
||||
.start()
|
||||
)
|
||||
.start();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isDebounced() {
|
||||
long currentTime = System.currentTimeMillis();
|
||||
if (currentTime - lastToggleTime < DEBOUNCE_INTERVAL) {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
lastToggleTime = currentTime;
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private void logDebug(String message) {
|
||||
Log.d(TAG, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,7 @@
|
||||
package com.auto.autoclicker;
|
||||
|
||||
import static com.auto.autoclicker.MainActivity.FLOATING_SINGLE;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
@ -33,11 +35,10 @@ 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
|
||||
);
|
||||
int type = intent != null ? intent.getIntExtra("FLOATING_TYPE", FLOATING_SINGLE) : FLOATING_SINGLE;
|
||||
|
||||
Intent notificationIntent = new Intent(this, MainActivity.class);
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE);
|
||||
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
|
||||
.setContentTitle("自动点击运行中")
|
||||
.setContentText("自动点击正在后台运行")
|
||||
@ -50,21 +51,20 @@ public class ForegroundService extends Service {
|
||||
|
||||
if (floatingViewManager != null && !isFloatingViewShown) {
|
||||
try {
|
||||
floatingViewManager.showFloatingViews();
|
||||
floatingViewManager.showFloatingViews(type);
|
||||
isFloatingViewShown = true;
|
||||
Log.d(TAG, "悬浮窗已显示");
|
||||
} catch (SecurityException e) {
|
||||
Log.e(TAG, "未授予悬浮窗权限", e);
|
||||
stopSelf();
|
||||
}
|
||||
} else if (floatingViewManager == null) {
|
||||
Log.e(TAG, "FloatingViewManager 未初始化");
|
||||
stopSelf();
|
||||
}
|
||||
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void createNotificationChannel() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
NotificationChannel channel = new NotificationChannel(
|
||||
|
||||
@ -23,17 +23,27 @@ import com.auto.autoclicker.util.PrefUtils;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
private static final String TAG = "MainActivity";
|
||||
private static final String ACTION_FLOATING_STATE_CHANGED = "com.auto.autoclicker.FLOATING_WINDOW_STATE_CHANGED";
|
||||
|
||||
private ActivityMainBinding binding;
|
||||
|
||||
public static final int FLOATING_NONE = 0;
|
||||
public static final int FLOATING_SINGLE = 1;
|
||||
public static final int FLOATING_MULTI = 2;
|
||||
|
||||
private Toast debounceToast;
|
||||
|
||||
private ActivityResultLauncher<Intent> permissionLauncher;
|
||||
|
||||
private long lastClickTime = 0;
|
||||
private static final long DEBOUNCE_INTERVAL = 500;
|
||||
private boolean isFloatingShown;
|
||||
private static final String ACTION_FLOATING_STATE_CHANGED = "com.auto.autoclicker.FLOATING_WINDOW_STATE_CHANGED";
|
||||
|
||||
private int isFloatingShown;
|
||||
|
||||
private final BroadcastReceiver floatingReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
isFloatingShown = intent.getBooleanExtra("isShown", false);
|
||||
isFloatingShown = intent.getIntExtra("isShown", 0);
|
||||
updateButtonText();
|
||||
}
|
||||
};
|
||||
@ -45,13 +55,14 @@ public class MainActivity extends AppCompatActivity {
|
||||
binding = ActivityMainBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
||||
isFloatingShown = PrefUtils.isFloatingShown(this);
|
||||
isFloatingShown = PrefUtils.getFloatingShown(this);
|
||||
updateButtonText();
|
||||
|
||||
LocalBroadcastManager.getInstance(this).registerReceiver(
|
||||
floatingReceiver, new IntentFilter(ACTION_FLOATING_STATE_CHANGED));
|
||||
|
||||
binding.singleButton.setOnClickListener(v -> onToggleFloatingWindowClicked());
|
||||
binding.singleButton.setOnClickListener(v -> onToggleFloatingWindowClicked(FLOATING_SINGLE));
|
||||
binding.moreButton.setOnClickListener(v -> onToggleFloatingWindowClicked(FLOATING_MULTI));
|
||||
|
||||
permissionLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> checkPermissions());
|
||||
|
||||
@ -120,24 +131,24 @@ public class MainActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
private void syncServiceState() {
|
||||
isFloatingShown = isServiceRunning();
|
||||
isFloatingShown = getFloatingMode();
|
||||
updateButtonText();
|
||||
}
|
||||
|
||||
private boolean isServiceRunning() {
|
||||
private int getFloatingMode() {
|
||||
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
|
||||
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
|
||||
if (ForegroundService.class.getName().equals(service.service.getClassName())) {
|
||||
return true;
|
||||
return PrefUtils.getFloatingShown(this);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void onToggleFloatingWindowClicked() {
|
||||
public void onToggleFloatingWindowClicked(int requestedType) {
|
||||
long currentTime = System.currentTimeMillis();
|
||||
if (currentTime - lastClickTime < DEBOUNCE_INTERVAL) {
|
||||
Toast.makeText(this, "点击太频繁", Toast.LENGTH_LONG).show();
|
||||
showDebounceToast();
|
||||
return;
|
||||
}
|
||||
lastClickTime = currentTime;
|
||||
@ -148,20 +159,28 @@ public class MainActivity extends AppCompatActivity {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isFloatingShown) {
|
||||
if (isFloatingShown != FLOATING_NONE && isFloatingShown != requestedType) {
|
||||
Toast.makeText(this, "已显示其他悬浮窗,请先关闭", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
if (isFloatingShown == requestedType) {
|
||||
stopService(new Intent(this, ForegroundService.class));
|
||||
AutoClickService.getInstance().stopClicking();
|
||||
isFloatingShown = false;
|
||||
isFloatingShown = FLOATING_NONE;
|
||||
logDebug("悬浮窗已经隐藏");
|
||||
} else {
|
||||
Intent serviceIntent = new Intent(this, ForegroundService.class);
|
||||
serviceIntent.putExtra("FLOATING_TYPE", requestedType);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
startForegroundService(serviceIntent);
|
||||
} else {
|
||||
startService(serviceIntent);
|
||||
}
|
||||
isFloatingShown = true;
|
||||
logDebug("悬浮窗已经显示");
|
||||
|
||||
isFloatingShown = requestedType;
|
||||
logDebug("悬浮窗已显示: " + requestedType);
|
||||
}
|
||||
|
||||
PrefUtils.setFloatingShown(this, isFloatingShown);
|
||||
@ -169,14 +188,14 @@ public class MainActivity extends AppCompatActivity {
|
||||
updateButtonText();
|
||||
}
|
||||
|
||||
private void broadcastFloatingState(boolean isShown) {
|
||||
private void broadcastFloatingState(int isShown) {
|
||||
Intent intent = new Intent(ACTION_FLOATING_STATE_CHANGED);
|
||||
intent.putExtra("isShown", isShown);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
|
||||
}
|
||||
|
||||
private void updateButtonText() {
|
||||
binding.singleButton.setText(isFloatingShown ? "隐藏悬浮窗" : "显示悬浮窗");
|
||||
binding.singleButton.setText(isFloatingShown == 1 ? "隐藏悬浮窗" : "显示悬浮窗");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -185,6 +204,15 @@ public class MainActivity extends AppCompatActivity {
|
||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(floatingReceiver);
|
||||
}
|
||||
|
||||
private void showDebounceToast() {
|
||||
if (debounceToast == null) {
|
||||
debounceToast = Toast.makeText(this, "点击太频繁", Toast.LENGTH_SHORT);
|
||||
} else {
|
||||
debounceToast.setText("点击太频繁");
|
||||
}
|
||||
debounceToast.show();
|
||||
}
|
||||
|
||||
private void logDebug(String message) {
|
||||
Log.d(TAG, message);
|
||||
}
|
||||
|
||||
@ -6,13 +6,13 @@ public class PrefUtils {
|
||||
private static final String PREF_NAME = "app_prefs";
|
||||
private static final String KEY_FLOATING_SHOWN = "floating_window_shown";
|
||||
|
||||
public static void setFloatingShown(Context context, boolean shown) {
|
||||
public static void setFloatingShown(Context context, int shown) {
|
||||
context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
|
||||
.edit().putBoolean(KEY_FLOATING_SHOWN, shown).apply();
|
||||
.edit().putInt(KEY_FLOATING_SHOWN, shown).apply();
|
||||
}
|
||||
|
||||
public static boolean isFloatingShown(Context context) {
|
||||
public static int getFloatingShown(Context context) {
|
||||
return context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
|
||||
.getBoolean(KEY_FLOATING_SHOWN, false);
|
||||
.getInt(KEY_FLOATING_SHOWN, 0);
|
||||
}
|
||||
}
|
||||
|
||||
12
app/src/main/res/drawable/pause.xml
Normal file
12
app/src/main/res/drawable/pause.xml
Normal 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="M512,42.7a469.3,469.3 0,1 0,469.3 469.3A469.3,469.3 0,0 0,512 42.7zM512,906.7a394.7,394.7 0,1 1,394.7 -394.7,395.1 395.1,0 0,1 -394.7,394.7z"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M427.2,332.1a37.3,37.3 0,0 0,-37.3 37.3v285.1a37.3,37.3 0,0 0,74.7 0V369.4a37.3,37.3 0,0 0,-37.3 -37.3zM596.8,332.1a37.3,37.3 0,0 0,-37.3 37.3v285.1a37.3,37.3 0,1 0,74.7 0V369.4a37.3,37.3 0,0 0,-37.3 -37.3z"/>
|
||||
</vector>
|
||||
@ -16,14 +16,14 @@
|
||||
android:src="@drawable/play" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/file_button"
|
||||
android:id="@+id/add_button"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:src="@drawable/save" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/eye_button"
|
||||
android:id="@+id/remove_button"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user