20251212_211940_525

This commit is contained in:
2025-12-12 21:19:52 +08:00
parent 268688b8d8
commit f591db6611
2 changed files with 110 additions and 38 deletions

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Fri Dec 12 13:12:27 GMT 2025
#Fri Dec 12 13:17:41 GMT 2025
stageCount=1
libraryProject=
baseVersion=15.12
publishVersion=15.12.0
buildCount=60
buildCount=61
baseBetaVersion=15.12.1

View File

@@ -22,12 +22,12 @@ import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import cc.winboll.studio.contacts.R;
import cc.winboll.studio.contacts.adapters.PhoneConnectRuleAdapter;
import cc.winboll.studio.contacts.bobulltoon.TomCat;
import cc.winboll.studio.contacts.dun.Rules;
import cc.winboll.studio.contacts.model.MainServiceBean;
import cc.winboll.studio.contacts.model.PhoneConnectRuleBean;
import cc.winboll.studio.contacts.model.RingTongBean;
import cc.winboll.studio.contacts.model.SettingsBean;
import cc.winboll.studio.contacts.bobulltoon.TomCat;
import cc.winboll.studio.contacts.dun.Rules;
import cc.winboll.studio.contacts.services.MainService;
import cc.winboll.studio.contacts.views.DuInfoTextView;
import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity;
@@ -40,12 +40,15 @@ import java.util.List;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/02/21 05:37:42
* @Describe Contacts 主窗口
* @Describe Contacts 设置页面(完全适配 API 30 + Java 7 语法)
* 核心优化1. 移除高版本API依赖 2. Java7规范写法 3. 强化内存泄漏防护 4. 版本判断硬编码
*/
public class SettingsActivity extends WinBollActivity implements IWinBoLLActivity {
// ====================== 常量定义区 ======================
public static final String TAG = "SettingsActivity";
// API版本硬编码常量替代Build.VERSION_CODES适配API30
private static final int ANDROID_6_API = 23;
// ====================== 静态控件区 ======================
static DuInfoTextView _DuInfoTextView;
@@ -108,7 +111,15 @@ public class SettingsActivity extends WinBollActivity implements IWinBoLLActivit
protected void onDestroy() {
super.onDestroy();
LogUtils.d(TAG, "onDestroy: 设置页面开始销毁");
_DuInfoTextView = null; // 清空静态引用,避免内存泄漏
// 清空静态引用 + 置空所有控件引用,彻底避免内存泄漏
_DuInfoTextView = null;
mToolbar = null;
mswMainService = null;
msbVolume = null;
mtvVolume = null;
recyclerView = null;
adapter = null;
ruleList = null;
LogUtils.d(TAG, "onDestroy: 设置页面销毁完成");
}
@@ -117,11 +128,12 @@ public class SettingsActivity extends WinBollActivity implements IWinBoLLActivit
LogUtils.d(TAG, "initToolbar: 初始化工具栏");
mToolbar = (Toolbar) findViewById(R.id.activitymainToolbar1);
setSupportActionBar(mToolbar);
// 显示后退按钮
// 显示后退按钮(添加空指针防护)
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setSubtitle(getTag());
}
// Java7 匿名内部类实现点击监听禁止Lambda
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -135,7 +147,14 @@ public class SettingsActivity extends WinBollActivity implements IWinBoLLActivit
LogUtils.d(TAG, "initMainServiceSwitch: 初始化主服务开关");
mswMainService = (Switch) findViewById(R.id.sw_mainservice);
MainServiceBean mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class);
mswMainService.setChecked(mMainServiceBean.isEnable());
// 空指针防护避免MainServiceBean为null导致崩溃
if (mMainServiceBean != null) {
mswMainService.setChecked(mMainServiceBean.isEnable());
} else {
mswMainService.setChecked(false);
LogUtils.w(TAG, "initMainServiceSwitch: MainServiceBean为null默认关闭开关");
}
mswMainService.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
@@ -155,6 +174,12 @@ public class SettingsActivity extends WinBollActivity implements IWinBoLLActivit
mtvVolume = (TextView) findViewById(R.id.tv_volume);
final AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
// 空指针防护AudioManager可能为null
if (audioManager == null) {
LogUtils.e(TAG, "initVolumeSeekBar: AudioManager获取失败跳过音量初始化");
return;
}
// 设置SeekBar最大值和初始进度
mnStreamMaxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_RING);
msbVolume.setMax(mnStreamMaxVolume);
@@ -162,7 +187,7 @@ public class SettingsActivity extends WinBollActivity implements IWinBoLLActivit
msbVolume.setProgress(mnStreamVolume);
updateStreamVolumeTextView();
// 音量调节监听
// 音量调节监听Java7匿名内部类
msbVolume.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
@@ -207,27 +232,37 @@ public class SettingsActivity extends WinBollActivity implements IWinBoLLActivit
swIsEnableDun = (Switch) findViewById(R.id.sw_IsEnableDun);
SettingsBean settingsModel = Rules.getInstance(this).getSettingsModel();
etDunTotalCount.setText(Integer.toString(settingsModel.getDunTotalCount()));
etDunResumeSecondCount.setText(Integer.toString(settingsModel.getDunResumeSecondCount()));
etDunResumeCount.setText(Integer.toString(settingsModel.getDunResumeCount()));
swIsEnableDun.setChecked(settingsModel.isEnableDun());
// 空指针防护避免SettingsModel为null
if (settingsModel != null) {
etDunTotalCount.setText(Integer.toString(settingsModel.getDunTotalCount()));
etDunResumeSecondCount.setText(Integer.toString(settingsModel.getDunResumeSecondCount()));
etDunResumeCount.setText(Integer.toString(settingsModel.getDunResumeCount()));
swIsEnableDun.setChecked(settingsModel.isEnableDun());
boolean isEnableDun = settingsModel.isEnableDun();
etDunTotalCount.setEnabled(!isEnableDun);
etDunResumeSecondCount.setEnabled(!isEnableDun);
etDunResumeCount.setEnabled(!isEnableDun);
boolean isEnableDun = settingsModel.isEnableDun();
etDunTotalCount.setEnabled(!isEnableDun);
etDunResumeSecondCount.setEnabled(!isEnableDun);
etDunResumeCount.setEnabled(!isEnableDun);
} else {
LogUtils.e(TAG, "initDunSettings: SettingsModel为null云盾设置初始化失败");
}
}
private void initBoBullToonViews() {
LogUtils.d(TAG, "initBoBullToonViews: 初始化BoBullToon相关控件");
etBoBullToonURL = (EditText) findViewById(R.id.bobulltoonurl_et);
etBoBullToonURL.setText(Rules.getInstance(this).getBoBullToonURL());
etPhone = (EditText) findViewById(R.id.activitysettingsEditText1);
// 空指针防护避免Rules.getInstance返回null
Rules rules = Rules.getInstance(this);
if (rules != null) {
etBoBullToonURL.setText(rules.getBoBullToonURL());
}
}
// ====================== 工具函数区 ======================
private void updateStreamVolumeTextView() {
mtvVolume.setText(String.format("%d/%d", mnStreamVolume, mnStreamMaxVolume));
// Java7 字符串拼接,避免String.format可能的空指针
mtvVolume.setText(mnStreamVolume + "/" + mnStreamMaxVolume);
}
// ====================== 静态通知函数区 ======================
@@ -249,15 +284,31 @@ public class SettingsActivity extends WinBollActivity implements IWinBoLLActivit
etDunResumeCount.setEnabled(!isEnableDun);
SettingsBean settingsModel = Rules.getInstance(this).getSettingsModel();
// 空指针防护SettingsModel为null时直接返回
if (settingsModel == null) {
LogUtils.e(TAG, "onSW_IsEnableDun: SettingsModel为null操作失败");
swIsEnableDun.setChecked(false);
return;
}
if (isEnableDun) {
try {
int totalCount = Integer.parseInt(etDunTotalCount.getText().toString());
int resumeSecond = Integer.parseInt(etDunResumeSecondCount.getText().toString());
int resumeCount = Integer.parseInt(etDunResumeCount.getText().toString());
String totalCountStr = etDunTotalCount.getText().toString().trim();
String resumeSecondStr = etDunResumeSecondCount.getText().toString().trim();
String resumeCountStr = etDunResumeCount.getText().toString().trim();
// 空字符串校验
if (totalCountStr.isEmpty() || resumeSecondStr.isEmpty() || resumeCountStr.isEmpty()) {
throw new NumberFormatException("参数不能为空");
}
int totalCount = Integer.parseInt(totalCountStr);
int resumeSecond = Integer.parseInt(resumeSecondStr);
int resumeCount = Integer.parseInt(resumeCountStr);
settingsModel.setDunTotalCount(totalCount);
settingsModel.setDunResumeSecondCount(resumeSecond);
settingsModel.setDunResumeCount(resumeCount);
ToastUtils.show((totalCount == 1) ? "电话骚扰防御力几乎为0。" : String.format("以下设置将在连拨%d次后接通电话。", totalCount));
// Java7 条件判断 + 字符串拼接
String toastMsg = (totalCount == 1) ? "电话骚扰防御力几乎为0。" : "以下设置将在连拨" + totalCount + "次后接通电话。";
ToastUtils.show(toastMsg);
LogUtils.d(TAG, "onSW_IsEnableDun: 云盾参数更新完成totalCount=" + totalCount);
} catch (NumberFormatException e) {
LogUtils.e(TAG, "onSW_IsEnableDun: 云盾参数格式错误", e);
@@ -284,9 +335,14 @@ public class SettingsActivity extends WinBollActivity implements IWinBoLLActivit
public void onAddNewConnectionRule(View view) {
LogUtils.d(TAG, "onAddNewConnectionRule: 添加新的连接规则");
Rules.getInstance(this).getPhoneBlacRuleBeanList().add(new PhoneConnectRuleBean());
Rules.getInstance(this).saveRules();
adapter.notifyDataSetChanged();
Rules rules = Rules.getInstance(this);
if (rules != null) {
rules.getPhoneBlacRuleBeanList().add(new PhoneConnectRuleBean());
rules.saveRules();
adapter.notifyDataSetChanged();
} else {
LogUtils.e(TAG, "onAddNewConnectionRule: Rules实例为null添加规则失败");
}
}
public void onDefaultPhone(View view) {
@@ -297,7 +353,8 @@ public class SettingsActivity extends WinBollActivity implements IWinBoLLActivit
public void onCanDrawOverlays(View view) {
LogUtils.d(TAG, "onCanDrawOverlays: 检查悬浮窗权限");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) {
// 版本判断硬编码替代Build.VERSION_CODES.M适配API30
if (Build.VERSION.SDK_INT >= ANDROID_6_API && !Settings.canDrawOverlays(this)) {
askForDrawOverlay();
} else {
ToastUtils.show("悬浮窗已开启");
@@ -307,32 +364,44 @@ public class SettingsActivity extends WinBollActivity implements IWinBoLLActivit
public void onCleanBoBullToonData(View view) {
LogUtils.d(TAG, "onCleanBoBullToonData: 清理BoBullToon数据");
TomCat tomCat = TomCat.getInstance(this);
tomCat.cleanBoBullToon();
ToastUtils.show("BoBullToon数据已清理");
if (tomCat != null) {
tomCat.cleanBoBullToon();
ToastUtils.show("BoBullToon数据已清理");
}
}
public void onResetBoBullToonURL(View view) {
LogUtils.d(TAG, "onResetBoBullToonURL: 重置BoBullToon URL");
Rules.getInstance(this).resetDefaultBoBullToonURL();
etBoBullToonURL.setText(Rules.getInstance(this).getBoBullToonURL());
ToastUtils.show("已重置 BoBullToon URL");
Rules rules = Rules.getInstance(this);
if (rules != null) {
rules.resetDefaultBoBullToonURL();
etBoBullToonURL.setText(rules.getBoBullToonURL());
ToastUtils.show("已重置 BoBullToon URL。");
}
}
public void onDownloadBoBullToon(View view) {
LogUtils.d(TAG, "onDownloadBoBullToon: 开始下载BoBullToon数据");
Rules rules = Rules.getInstance(this);
if (rules == null) {
LogUtils.e(TAG, "onDownloadBoBullToon: Rules实例为null下载失败");
return;
}
String inputUrl = etBoBullToonURL.getText().toString().trim();
String savedUrl = Rules.getInstance(this).getBoBullToonURL();
String savedUrl = rules.getBoBullToonURL();
if (!inputUrl.equals(savedUrl)) {
Rules.getInstance(this).setBoBullToonURL(inputUrl);
rules.setBoBullToonURL(inputUrl);
LogUtils.d(TAG, "onDownloadBoBullToon: BoBullToon URL已更新为" + inputUrl);
}
final TomCat tomCat = TomCat.getInstance(this);
// Java7 匿名内部类实现Runnable禁止Lambda
new Thread(new Runnable() {
@Override
public void run() {
if (tomCat.downloadBoBullToon()) {
if (tomCat != null && tomCat.downloadBoBullToon()) {
LogUtils.d(TAG, "onDownloadBoBullToon: BoBullToon 下载成功");
// 主线程更新UIJava7 匿名内部类)
runOnUiThread(new Runnable() {
@Override
public void run() {
@@ -356,9 +425,10 @@ public class SettingsActivity extends WinBollActivity implements IWinBoLLActivit
ToastUtils.show("请输入要查询的号码");
return;
}
if (tomCat.loadPhoneBoBullToon()) {
if (tomCat != null && tomCat.loadPhoneBoBullToon()) {
boolean isBoBullToon = tomCat.isPhoneBoBullToon(phone);
ToastUtils.show(isBoBullToon ? "It is a BoBullToon Phone!" : "Not in BoBullToon.");
String toastMsg = isBoBullToon ? "It is a BoBullToon Phone!" : "Not in BoBullToon.";
ToastUtils.show(toastMsg);
LogUtils.d(TAG, "onSearchBoBullToonPhone: 号码" + phone + "查询结果:" + (isBoBullToon ? "" : "") + "为BoBullToon号码");
} else {
ToastUtils.show("没有下载 BoBullToon。");
@@ -378,6 +448,7 @@ public class SettingsActivity extends WinBollActivity implements IWinBoLLActivit
// ====================== 悬浮窗权限请求函数区 ======================
private void askForDrawOverlay() {
LogUtils.d(TAG, "askForDrawOverlay: 弹出悬浮窗权限请求对话框");
// Java7 匿名内部类实现Dialog监听
AlertDialog alertDialog = new AlertDialog.Builder(this)
.setTitle("允许显示悬浮框")
.setMessage("为了使电话监听服务正常工作,请允许这项权限")
@@ -406,7 +477,8 @@ public class SettingsActivity extends WinBollActivity implements IWinBoLLActivit
private void openDrawOverlaySettings() {
LogUtils.d(TAG, "openDrawOverlaySettings: 跳转悬浮窗管理设置界面");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// 版本判断硬编码
if (Build.VERSION.SDK_INT >= ANDROID_6_API) {
try {
Context context = this;
Class<?> clazz = Settings.class;