From f591db6611a863e82e5a3abc872a71808a59d0f4 Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Fri, 12 Dec 2025 21:19:52 +0800 Subject: [PATCH] 20251212_211940_525 --- contacts/build.properties | 4 +- .../contacts/activities/SettingsActivity.java | 144 +++++++++++++----- 2 files changed, 110 insertions(+), 38 deletions(-) diff --git a/contacts/build.properties b/contacts/build.properties index 603b9ca..57b9903 100644 --- a/contacts/build.properties +++ b/contacts/build.properties @@ -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 diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/activities/SettingsActivity.java b/contacts/src/main/java/cc/winboll/studio/contacts/activities/SettingsActivity.java index ce26aa4..d6601f7 100644 --- a/contacts/src/main/java/cc/winboll/studio/contacts/activities/SettingsActivity.java +++ b/contacts/src/main/java/cc/winboll/studio/contacts/activities/SettingsActivity.java @@ -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&豆包大模型 * @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 下载成功"); + // 主线程更新UI(Java7 匿名内部类) 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;