version:2.2.1

bugfixes:优化自动拨号和权限问题
update:
This commit is contained in:
2025-07-28 09:42:34 +08:00
parent 6d44cb8b7a
commit a992e40182
3 changed files with 115 additions and 47 deletions

View File

@@ -18,8 +18,8 @@ android {
minSdkVersion 24 minSdkVersion 24
targetSdkVersion 29 targetSdkVersion 29
versionCode 220 versionCode 221
versionName "2.2.0" versionName "2.2.1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

View File

@@ -12,7 +12,6 @@ import android.graphics.Point;
import android.graphics.Rect; import android.graphics.Rect;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import android.util.Log; import android.util.Log;
@@ -31,9 +30,17 @@ import com.vscool.os.utils.ForegroundAppUtil;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.Random; import java.util.Random;
import java.util.concurrent.TimeUnit;
import io.reactivex.rxjava3.annotations.NonNull;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.core.ObservableEmitter;
import io.reactivex.rxjava3.core.ObservableOnSubscribe;
import io.reactivex.rxjava3.functions.Consumer;
/** /**
* 通过微信标签最高支持8.0.498.0.50 获取不到数据 * 通过微信标签最高支持8.0.498.0.50 获取不到数据
* 8.0.54 可以获取
* 通过 {@link AccessibilityService#getWindows}和修改accessibility-service 配置能遍历屏幕元素 * 通过 {@link AccessibilityService#getWindows}和修改accessibility-service 配置能遍历屏幕元素
*/ */
public class SelectToSpeakService extends AccessibilityService { public class SelectToSpeakService extends AccessibilityService {
@@ -63,7 +70,7 @@ public class SelectToSpeakService extends AccessibilityService {
public static final int TYPE_VOICE = 0; public static final int TYPE_VOICE = 0;
public static final int TYPE_VIDEO = 1; public static final int TYPE_VIDEO = 1;
private static final int WAIT_TIME = 1200; private static final int WAIT_TIME = 1300;
private int mCallType = TYPE_VOICE; private int mCallType = TYPE_VOICE;
@@ -72,17 +79,12 @@ public class SelectToSpeakService extends AccessibilityService {
private String mName = "";//微信昵称 private String mName = "";//微信昵称
private String mTagName = "";//微信联系人标签名 private String mTagName = "";//微信联系人标签名
private boolean mAutoAccept = false; private boolean mAutoAccept = false;
private boolean finished = true;
private Handler handler = null; public interface AccessibilityEventCallback {
private AccessibilityEvent input = null; void onAccessibilityEventCallback(AccessibilityEvent accessibilityEvent);
private Runnable runnable = new Runnable() { }
@Override
public void run() { private AccessibilityEventCallback mAccessibilityEventCallback;
_onAccessibilityEvent(input);
finished = true;
}
};
@Override @Override
public void onCreate() { public void onCreate() {
@@ -90,10 +92,27 @@ public class SelectToSpeakService extends AccessibilityService {
Log.e(TAG, "onCreate: "); Log.e(TAG, "onCreate: ");
registerSettingReceiver(); registerSettingReceiver();
mAutoAccept = mMMKV.decodeBool(CommonConfig.WECHAT_CALL_AUTO_ACCEPT, false); mAutoAccept = mMMKV.decodeBool(CommonConfig.WECHAT_CALL_AUTO_ACCEPT, false);
handler = new Handler(); analysisAccessibilityEvent();
}
private void analysisAccessibilityEvent() {
Observable.create(new ObservableOnSubscribe<AccessibilityEvent>() {
@Override
public void subscribe(@NonNull ObservableEmitter<AccessibilityEvent> emitter) throws Throwable {
mAccessibilityEventCallback = emitter::onNext;
}
}).throttleLast(WAIT_TIME, TimeUnit.MILLISECONDS)
.subscribe(new Consumer<AccessibilityEvent>() {
@Override
public void accept(AccessibilityEvent accessibilityEvent) throws Throwable {
Log.e(TAG, "analysisAccessibilityEvent accept: ");
_onAccessibilityEvent(accessibilityEvent);
}
});
} }
@Override @Override
public int onStartCommand(Intent intent, int flags, int startId) { public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand: "); Log.e(TAG, "onStartCommand: ");
@@ -127,14 +146,7 @@ public class SelectToSpeakService extends AccessibilityService {
public void onAccessibilityEvent(AccessibilityEvent event) { public void onAccessibilityEvent(AccessibilityEvent event) {
Log.v(TAG, "onAccessibilityEvent: event = " + event.toString()); Log.v(TAG, "onAccessibilityEvent: event = " + event.toString());
checkClassName(event); checkClassName(event);
if (finished) { mAccessibilityEventCallback.onAccessibilityEventCallback(event);
finished = false;
} else {
Log.v(TAG, "bounce");
handler.removeCallbacks(runnable);
}
input = event;
handler.postDelayed(runnable, WAIT_TIME);
} }
private void checkClassName(AccessibilityEvent event) { private void checkClassName(AccessibilityEvent event) {
@@ -421,8 +433,7 @@ public class SelectToSpeakService extends AccessibilityService {
clickNode(nodeInfo); clickNode(nodeInfo);
mCurrentStep = nextStep; mCurrentStep = nextStep;
} else { } else {
Toaster.show("没有找到控件"); Toaster.show("没有找到搜索按钮");
mCurrentStep = Step.WAITING;
} }
} }

View File

@@ -85,7 +85,12 @@ public class SettingActivity extends BaseMvvmActivity<SettingViewModel, Activity
@Override @Override
public void onToggle(boolean on) { public void onToggle(boolean on) {
if (on) { if (on) {
showFloatingWindow(); boolean permission = checkFloatPermission(SettingActivity.this);
if (permission) {
showFloatingWindow();
} else {
showFloatWindowDialog();
}
} else { } else {
hideFloatingWindow(); hideFloatingWindow();
} }
@@ -221,28 +226,40 @@ public class SettingActivity extends BaseMvvmActivity<SettingViewModel, Activity
@Override @Override
protected void onResume() { protected void onResume() {
super.onResume(); super.onResume();
Log.e(TAG, "onResume: ");
setStatus(); setStatus();
mViewModel.getSystemSettings(); mViewModel.getSystemSettings();
} }
private void setStatus() { private void setStatus() {
boolean showFloatWindow = Settings.Global.getInt(getContentResolver(), CommonConfig.HOVER_HOME, CommonConfig.HOVER_HOME_STATUS) == 1; boolean showFloatWindow = Settings.Global.getInt(getContentResolver(), CommonConfig.HOVER_HOME, CommonConfig.HOVER_HOME_STATUS) == 1;
Log.e(TAG, "initView: showFloatWindow = " + showFloatWindow); Log.e(TAG, "setStatus: showFloatWindow = " + showFloatWindow);
mViewDataBinding.tbFloat.setToggleStatu(showFloatWindow); mViewDataBinding.tbFloat.setToggleStatu(showFloatWindow);
if (showFloatWindow) {
boolean permission = checkFloatPermission(SettingActivity.this);
if (permission) {
showFloatingWindow();
} else {
showFloatWindowDialog();
}
} else {
hideFloatingWindow();
}
boolean voiceBroadcast = mMMKV.decodeBool(CommonConfig.VOICE_BROADCAST, false); boolean voiceBroadcast = mMMKV.decodeBool(CommonConfig.VOICE_BROADCAST, false);
Log.e(TAG, "initView: voiceBroadcast = " + voiceBroadcast); Log.e(TAG, "setStatus: voiceBroadcast = " + voiceBroadcast);
mViewDataBinding.tbSms.setToggleStatu(voiceBroadcast); mViewDataBinding.tbSms.setToggleStatu(voiceBroadcast);
boolean autoAccept = mMMKV.decodeBool(CommonConfig.WECHAT_CALL_AUTO_ACCEPT, false); boolean autoAccept = mMMKV.decodeBool(CommonConfig.WECHAT_CALL_AUTO_ACCEPT, false);
Log.e(TAG, "initView: autoAccept = " + autoAccept); Log.e(TAG, "setStatus: autoAccept = " + autoAccept);
mViewDataBinding.tbAutoAnswer.setToggleStatu(autoAccept); mViewDataBinding.tbAutoAnswer.setToggleStatu(autoAccept);
if (autoAccept) { if (autoAccept) {
boolean floatWindowEnable = Settings.Global.getInt(getContentResolver(), CommonConfig.HOVER_HOME, CommonConfig.HOVER_HOME_STATUS) == 1; boolean floatWindowEnable = Settings.Global.getInt(getContentResolver(), CommonConfig.HOVER_HOME, CommonConfig.HOVER_HOME_STATUS) == 1;
boolean permission = FloatingWindowUtils.checkFloatPermission(SettingActivity.this); boolean permission = FloatingWindowUtils.checkFloatPermission(SettingActivity.this);
if (floatWindowEnable && permission) { boolean accessibility = AccessibilityUtils.isAccessibilitySettingsOn(SettingActivity.this);
if (floatWindowEnable && permission && !accessibility) {
Toast.makeText(SettingActivity.this, "由于系统限制,请先关闭悬浮窗功能,开启自动接听后再打开悬浮窗", Toast.LENGTH_LONG).show(); Toast.makeText(SettingActivity.this, "由于系统限制,请先关闭悬浮窗功能,开启自动接听后再打开悬浮窗", Toast.LENGTH_LONG).show();
showFloatWindowDialog(); showFloatHideDialog();
} else { } else {
if (AccessibilityUtils.isAccessibilitySettingsOn(SettingActivity.this)) { if (AccessibilityUtils.isAccessibilitySettingsOn(SettingActivity.this)) {
mMMKV.encode(CommonConfig.WECHAT_CALL_AUTO_ACCEPT, 1); mMMKV.encode(CommonConfig.WECHAT_CALL_AUTO_ACCEPT, 1);
@@ -256,32 +273,32 @@ public class SettingActivity extends BaseMvvmActivity<SettingViewModel, Activity
} }
boolean wxAutoVideo = mMMKV.decodeInt(CommonConfig.WECHAT_AUTO_CALL_KEY, 0) == 1; boolean wxAutoVideo = mMMKV.decodeInt(CommonConfig.WECHAT_AUTO_CALL_KEY, 0) == 1;
Log.e(TAG, "initView: wxAutoVideo = " + autoAccept); Log.e(TAG, "setStatus: wxAutoVideo = " + autoAccept);
mViewDataBinding.tbAutoCall.setToggleStatu(wxAutoVideo); mViewDataBinding.tbAutoCall.setToggleStatu(wxAutoVideo);
boolean dialTone = mMMKV.decodeBool(CommonConfig.DISABLE_DIAL_TONE_MODIFY, true); boolean dialTone = mMMKV.decodeBool(CommonConfig.DISABLE_DIAL_TONE_MODIFY, true);
Log.e(TAG, "initView: dialTone = " + dialTone); Log.e(TAG, "setStatus: dialTone = " + dialTone);
mViewDataBinding.tbDialer.setToggleStatu(dialTone); mViewDataBinding.tbDialer.setToggleStatu(dialTone);
int code = Settings.System.getInt(getContentResolver(), CommonConfig.ACTION_STATUS_BAR_STATE, 0); int code = Settings.System.getInt(getContentResolver(), CommonConfig.ACTION_STATUS_BAR_STATE, 0);
boolean statusBar = code == 1; boolean statusBar = code == 1;
Log.e(TAG, "initView: statusBar = " + statusBar); Log.e(TAG, "setStatus: statusBar = " + statusBar);
mViewDataBinding.tbStatu.setToggleStatu(statusBar); mViewDataBinding.tbStatu.setToggleStatu(statusBar);
boolean hourlyTime = mMMKV.decodeBool(CommonConfig.HOURLY_TIME_SIGNAL_KEY, false); boolean hourlyTime = mMMKV.decodeBool(CommonConfig.HOURLY_TIME_SIGNAL_KEY, false);
Log.e(TAG, "initView: hourlyTime = " + hourlyTime); Log.e(TAG, "setStatus: hourlyTime = " + hourlyTime);
mViewDataBinding.tbHourly.setToggleStatu(hourlyTime); mViewDataBinding.tbHourly.setToggleStatu(hourlyTime);
boolean disableKey = mMMKV.decodeBool(CommonConfig.DISABLE_VOLUME_KEY, false); boolean disableKey = mMMKV.decodeBool(CommonConfig.DISABLE_VOLUME_KEY, false);
Log.e(TAG, "initView: disableKey = " + disableKey); Log.e(TAG, "setStatus: disableKey = " + disableKey);
mViewDataBinding.tbVolume.setToggleStatu(!disableKey); mViewDataBinding.tbVolume.setToggleStatu(!disableKey);
boolean contactModify = mMMKV.decodeBool(CommonConfig.DISABLE_CONTACT_MODIFY, false); boolean contactModify = mMMKV.decodeBool(CommonConfig.DISABLE_CONTACT_MODIFY, false);
Log.e(TAG, "initView: contactModify = " + contactModify); Log.e(TAG, "setStatus: contactModify = " + contactModify);
mViewDataBinding.tbContact.setToggleStatu(!contactModify); mViewDataBinding.tbContact.setToggleStatu(!contactModify);
int clockModify = mMMKV.decodeInt(CommonConfig.ALARM_CLOCK_CTRL, 1); int clockModify = mMMKV.decodeInt(CommonConfig.ALARM_CLOCK_CTRL, 1);
Log.e(TAG, "initView: clockModify = " + clockModify); Log.e(TAG, "setStatus: clockModify = " + clockModify);
mViewDataBinding.tbClock.setToggleStatu(clockModify == 1); mViewDataBinding.tbClock.setToggleStatu(clockModify == 1);
} }
@@ -390,9 +407,10 @@ public class SettingActivity extends BaseMvvmActivity<SettingViewModel, Activity
public void onPositive() { public void onPositive() {
boolean floatWindowEnable = Settings.Global.getInt(getContentResolver(), CommonConfig.HOVER_HOME, CommonConfig.HOVER_HOME_STATUS) == 1; boolean floatWindowEnable = Settings.Global.getInt(getContentResolver(), CommonConfig.HOVER_HOME, CommonConfig.HOVER_HOME_STATUS) == 1;
boolean permission = FloatingWindowUtils.checkFloatPermission(SettingActivity.this); boolean permission = FloatingWindowUtils.checkFloatPermission(SettingActivity.this);
if (floatWindowEnable && permission) { boolean accessibility = AccessibilityUtils.isAccessibilitySettingsOn(SettingActivity.this);
if (floatWindowEnable && permission && !accessibility) {
Toast.makeText(SettingActivity.this, "由于系统限制,请先关闭悬浮窗功能,开启自动接听后再打开悬浮窗", Toast.LENGTH_LONG).show(); Toast.makeText(SettingActivity.this, "由于系统限制,请先关闭悬浮窗功能,开启自动接听后再打开悬浮窗", Toast.LENGTH_LONG).show();
showFloatWindowDialog(); showFloatHideDialog();
} else { } else {
showAutoAcceptDialog(); showAutoAcceptDialog();
} }
@@ -433,7 +451,6 @@ public class SettingActivity extends BaseMvvmActivity<SettingViewModel, Activity
// } // }
} }
private PermissionsDialog mFloatWindowDialog;
private void setWechatAutoCall(boolean on) { private void setWechatAutoCall(boolean on) {
if (on) { if (on) {
@@ -462,6 +479,37 @@ public class SettingActivity extends BaseMvvmActivity<SettingViewModel, Activity
} }
} }
private PermissionsDialog mFloatWindowHideDialog;
private void showFloatHideDialog() {
if (mFloatWindowHideDialog != null) {
mFloatWindowHideDialog.dismiss();
mFloatWindowHideDialog = null;
}
mFloatWindowHideDialog = new PermissionsDialog(SettingActivity.this);
mFloatWindowHideDialog.setTitle("功能说明");
mFloatWindowHideDialog.setContent("由于系统限制,请先关闭悬浮窗功能,开启自动接听后再打开悬浮窗");
mFloatWindowHideDialog.setDeniedtext("取消");
mFloatWindowHideDialog.setGrantedtext("确定");
mFloatWindowHideDialog.setPermissionsCallback(new PermissionsDialog.PermissionsCallback() {
@Override
public void onGranted() {
mFloatWindowHideDialog.dismiss();
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
startActivity(intent);
}
@Override
public void onDenied() {
mFloatWindowHideDialog.dismiss();
mViewDataBinding.tbAutoAnswer.setToggleStatu(false);
}
});
mFloatWindowHideDialog.show();
}
private PermissionsDialog mFloatWindowDialog;
private void showFloatWindowDialog() { private void showFloatWindowDialog() {
if (mFloatWindowDialog != null) { if (mFloatWindowDialog != null) {
mFloatWindowDialog.dismiss(); mFloatWindowDialog.dismiss();
@@ -469,21 +517,29 @@ public class SettingActivity extends BaseMvvmActivity<SettingViewModel, Activity
} }
mFloatWindowDialog = new PermissionsDialog(SettingActivity.this); mFloatWindowDialog = new PermissionsDialog(SettingActivity.this);
mFloatWindowDialog.setTitle("功能说明"); mFloatWindowDialog.setTitle("功能说明");
mFloatWindowDialog.setContent("由于系统限制,请先关闭悬浮窗功能,开启自动接听后再打开悬浮窗"); mFloatWindowDialog.setContent("您已开启悬浮窗功能,程序需要授予悬浮窗权限才能使用此功能,是否同意授权");
mFloatWindowDialog.setDeniedtext("取消"); mFloatWindowDialog.setDeniedtext("取消");
mFloatWindowDialog.setGrantedtext("确定"); mFloatWindowDialog.setGrantedtext("确定");
mFloatWindowDialog.setPermissionsCallback(new PermissionsDialog.PermissionsCallback() { mFloatWindowDialog.setPermissionsCallback(new PermissionsDialog.PermissionsCallback() {
@Override @Override
public void onGranted() { public void onGranted() {
mFloatWindowDialog.dismiss(); // 在Activity或Fragment中请求权限
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())); if (!Settings.canDrawOverlays(SettingActivity.this)) {
startActivity(intent); Toast.makeText(SettingActivity.this, "请先打开悬浮窗权限", Toast.LENGTH_LONG).show();
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, REQUEST_CODE_DRAW_OVER_OTHER_APPS_PERMISSION);
} else {
showFloatingWindow();
mFloatWindowDialog.dismiss();
}
} }
@Override @Override
public void onDenied() { public void onDenied() {
mFloatWindowDialog.dismiss(); mFloatWindowDialog.dismiss();
mViewDataBinding.tbAutoAnswer.setToggleStatu(false); mViewDataBinding.tbFloat.setToggleStatu(false);
Settings.Global.putInt(getContentResolver(), CommonConfig.HOVER_HOME, 0);
} }
}); });
mFloatWindowDialog.show(); mFloatWindowDialog.show();
@@ -510,10 +566,11 @@ public class SettingActivity extends BaseMvvmActivity<SettingViewModel, Activity
public void onGranted() { public void onGranted() {
mAutoAcceptDialog.dismiss(); mAutoAcceptDialog.dismiss();
if (AccessibilityUtils.isAccessibilitySettingsOn(SettingActivity.this)) { if (AccessibilityUtils.isAccessibilitySettingsOn(SettingActivity.this)) {
mMMKV.encode(CommonConfig.WECHAT_CALL_AUTO_ACCEPT, 1);
Intent intent = new Intent(SelectToSpeakService.SETTING_AUTOMATIC_ANSWER_ACTION); Intent intent = new Intent(SelectToSpeakService.SETTING_AUTOMATIC_ANSWER_ACTION);
intent.putExtra("auto_answer", true); intent.putExtra("auto_answer", true);
sendBroadcast(intent); sendBroadcast(intent);
mMMKV.encode(CommonConfig.WECHAT_CALL_AUTO_ACCEPT, 1);
mViewDataBinding.tbAutoAnswer.setToggleStatu(true);
} else { } else {
AccessibilityUtils.openAccessibilitySettings(SettingActivity.this); AccessibilityUtils.openAccessibilitySettings(SettingActivity.this);
} }