diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java b/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java index 7cb8810..4f4618d 100644 --- a/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java +++ b/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java @@ -4,21 +4,16 @@ import android.Manifest; import android.app.Activity; import android.app.ActivityManager; import android.app.AlertDialog; -import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; -import android.content.ServiceConnection; import android.graphics.Color; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Handler; -import android.os.IBinder; import android.os.Looper; import android.telecom.TelecomManager; -import android.telephony.PhoneStateListener; -import android.telephony.TelephonyManager; import android.view.Menu; import android.view.MenuItem; import android.view.View; @@ -41,7 +36,6 @@ import cc.winboll.studio.contacts.fragments.ContactsFragment; import cc.winboll.studio.contacts.fragments.LogFragment; import cc.winboll.studio.contacts.model.MainServiceBean; import cc.winboll.studio.contacts.services.MainService; -import cc.winboll.studio.contacts.services.MyCallScreeningService; import cc.winboll.studio.contacts.utils.PermissionUtils; import cc.winboll.studio.contacts.views.DunTemperatureView; import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity; @@ -57,7 +51,7 @@ import java.util.List; * @Author ZhanGSKen&豆包大模型 * @Date 2025/08/30 14:32 * @Describe Contacts 主窗口(完全适配 API 30 + Java 7 语法) - * 核心优化:1. 与MainService状态联动 2. 移除高版本API依赖 3. 强化资源释放 4. Java7规范写法 + * 核心优化:1. 移除电话状态监听 2. 移除通话筛选服务 3. 移除 MainService 绑定 4. 保留原有页面结构 */ public final class MainActivity extends WinBollActivity implements IWinBoLLActivity, ViewPager.OnPageChangeListener, View.OnClickListener { @@ -70,7 +64,6 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv private static final int DIALER_REQUEST_CODE = 1; private static final int REQUEST_REQUIRED_PERMISSIONS = 1002; private static final int REQUEST_OVERLAY_PERMISSION = 1003; - private static final int REQUEST_CALL_SCREENING_PERMISSION = 1004; // API版本硬编码常量(Java 7兼容,杜绝Build.VERSION_CODES高版本引用) private static final int ANDROID_6_API = 23; @@ -98,13 +91,8 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv // ====================== 5. 业务逻辑成员区 ====================== private MainServiceBean mMainServiceBean; private int currentPoint = 0; - private TelephonyManager telephonyManager; - private MyPhoneStateListener phoneStateListener; private List fragmentList; private List tabTitleList; - // 新增:ServiceConnection,用于与MainService绑定并传递窗口状态 - private MainServiceConnection mMainServiceConnection; - private boolean mIsServiceBound = false; // ====================== 6. 接口实现区 ====================== @Override @@ -124,9 +112,6 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv LogUtils.d(TAG, "===== onCreate: 主Activity开始创建 ====="); _MainActivity = this; - // 初始化ServiceConnection - mMainServiceConnection = new MainServiceConnection(); - // 直接初始化UI(原权限检查逻辑注释保留,按需启用) initUIAndLogic(savedInstanceState); LogUtils.d(TAG, "===== onCreate: 主Activity创建流程结束 ====="); @@ -145,15 +130,13 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv mADsBannerView.resumeADs(MainActivity.this); LogUtils.d(TAG, "onResume: 广告栏资源已恢复"); } - // 绑定MainService,用于传递窗口状态 - bindMainService(); + // 移除 MainService 绑定逻辑 } @Override protected void onPause() { super.onPause(); - // 解绑MainService,避免内存泄漏 - unbindMainService(); + // 移除 MainService 解绑逻辑 } @Override @@ -165,28 +148,8 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv mADsBannerView.releaseAdResources(); LogUtils.d(TAG, "onDestroy: 广告栏资源已释放"); } - // 移除电话状态监听,防止内存泄漏 - if (telephonyManager != null && phoneStateListener != null) { - telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE); - LogUtils.d(TAG, "onDestroy: 电话状态监听器已移除"); - } - // 解绑MainService并通知窗口销毁状态 - unbindMainService(); - // 最后尝试绑定一次,传递销毁状态(防止解绑后未传递) - final Intent intent = new Intent(this, MainService.class); - bindService(intent, new ServiceConnection() { - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - MainService.MyBinder binder = (MainService.MyBinder) service; - binder.setMainWindowDestroyed(true); - unbindService(this); - LogUtils.d(TAG, "onDestroy: 已通知MainService窗口销毁状态"); - } - - @Override - public void onServiceDisconnected(ComponentName name) {} - }, Context.BIND_AUTO_CREATE); - + // 移除电话状态监听释放逻辑(已删除监听初始化,无需释放) + // 移除 MainService 解绑及状态传递逻辑 LogUtils.d(TAG, "===== onDestroy: 主Activity销毁完成 ====="); } @@ -227,9 +190,7 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv case REQUEST_OVERLAY_PERMISSION: handleOverlayPermissionResult(); break; - case REQUEST_CALL_SCREENING_PERMISSION: - handleCallScreeningPermissionResult(); - break; + // 移除 通话筛选权限回调(REQUEST_CALL_SCREENING_PERMISSION)分支 default: LogUtils.w(TAG, "onActivityResult: 未知requestCode=" + requestCode); break; @@ -242,7 +203,9 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv private void handleOverlayPermissionResult() { if (PermissionUtils.isOverlayPermissionGranted(this)) { LogUtils.d(TAG, "handleOverlayPermissionResult: 悬浮窗权限申请成功"); - checkAndRequestRemainingPermissions(); + // 移除 通话筛选权限检查(直接完成权限流程) + LogUtils.d(TAG, "handleOverlayPermissionResult: 所有权限已授予"); + initUIAndLogic(null); } else { LogUtils.e(TAG, "handleOverlayPermissionResult: 悬浮窗权限申请失败"); showPermissionDeniedDialogAndExit("应用需要悬浮窗权限才能展示来电弹窗,请授予后重新打开应用。"); @@ -250,28 +213,12 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv } /** - * 处理通话筛选权限申请结果 - */ - private void handleCallScreeningPermissionResult() { - if (PermissionUtils.isCallScreeningPermissionGranted(this)) { - LogUtils.d(TAG, "handleCallScreeningPermissionResult: 通话筛选权限申请成功"); - initUIAndLogic(null); - } else { - LogUtils.e(TAG, "handleCallScreeningPermissionResult: 通话筛选权限申请失败"); - showPermissionDeniedDialogAndExit("应用需要通话筛选权限监听外拨电话,请授予后重新打开应用。"); - } - } - - /** - * 检查并申请剩余权限(悬浮窗+通话筛选) + * 检查并申请剩余权限(仅保留悬浮窗,移除通话筛选权限) */ private void checkAndRequestRemainingPermissions() { if (!PermissionUtils.isOverlayPermissionGranted(this)) { LogUtils.d(TAG, "checkAndRequestRemainingPermissions: 悬浮窗权限未授予,跳转设置页"); PermissionUtils.requestOverlayPermission(this, REQUEST_OVERLAY_PERMISSION); - } else if (Build.VERSION.SDK_INT >= ANDROID_10_API && !PermissionUtils.isCallScreeningPermissionGranted(this)) { - LogUtils.d(TAG, "checkAndRequestRemainingPermissions: 通话筛选权限未授予,跳转设置页"); - PermissionUtils.requestCallScreeningPermission(this, REQUEST_CALL_SCREENING_PERMISSION); } else { LogUtils.d(TAG, "checkAndRequestRemainingPermissions: 所有权限已授予"); initUIAndLogic(null); @@ -336,13 +283,11 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv mADsBannerView = (ADsBannerView) findViewById(R.id.adsbanner); LogUtils.d(TAG, "initUIAndLogic: 广告栏控件初始化完成"); - // 4. 主服务初始化 + // 4. 主服务初始化(保留启动逻辑,移除绑定相关) initMainService(); LogUtils.d(TAG, "initUIAndLogic: 主服务初始化完成"); - // 5. 电话状态监听初始化 - initPhoneStateListener(); - LogUtils.d(TAG, "initUIAndLogic: 电话状态监听器初始化完成"); + // 5. 移除 电话状态监听初始化逻辑(initPhoneStateListener() 调用删除) // 左边盾值视图初始化(Java7分步写法,禁止链式调用) DunTemperatureView tempViewLeft = (DunTemperatureView) findViewById(R.id.dun_temp_view_left); @@ -402,7 +347,7 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv } /** - * 初始化主服务(优化:延迟启动,降低主线程压力) + * 初始化主服务(保留启动逻辑,移除绑定相关;优化启动方式为静态方法) */ private void initMainService() { LogUtils.d(TAG, "initMainService: 开始初始化主服务配置"); @@ -414,13 +359,13 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv MainServiceBean.saveBean(this, mMainServiceBean); } - // 检查服务状态并启动 + // 检查服务状态并启动(使用静态方法,无绑定依赖) if (mMainServiceBean.isEnable() && !isServiceRunning(MainService.class)) { LogUtils.d(TAG, "initMainService: 主服务已启用且未运行,延迟1秒启动"); new Handler(Looper.getMainLooper()).postDelayed(new Runnable() { @Override public void run() { - MainService.startMainService(MainActivity.this); + MainService.startMainServiceAndSaveStatus(MainActivity.this); LogUtils.d(TAG, "initMainService: 主服务启动任务执行"); } }, 1000); @@ -430,61 +375,7 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv } } - /** - * 初始化电话状态监听与通话筛选服务(适配API30,移除高版本依赖) - */ - private void initPhoneStateListener() { - LogUtils.d(TAG, "initPhoneStateListener: 开始初始化电话监听"); - telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); - phoneStateListener = new MyPhoneStateListener(); - telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); - - // API 10+ 启动通话筛选服务(硬编码版本判断) - if (Build.VERSION.SDK_INT >= ANDROID_10_API) { - Intent screeningIntent = new Intent(this, MyCallScreeningService.class); - if (Build.VERSION.SDK_INT >= ANDROID_8_API) { - startForegroundService(screeningIntent); - LogUtils.d(TAG, "initPhoneStateListener: 以前台服务方式启动通话筛选服务"); - } else { - startService(screeningIntent); - LogUtils.d(TAG, "initPhoneStateListener: 以普通服务方式启动通话筛选服务"); - } - } - LogUtils.d(TAG, "initPhoneStateListener: 电话监听初始化完成"); - } - - // ====================== 10. MainService绑定/解绑工具方法 ====================== - /** - * 绑定MainService,用于传递窗口状态 - */ - private void bindMainService() { - if (mIsServiceBound) { - return; - } - Intent intent = new Intent(this, MainService.class); - boolean bindSuccess = bindService(intent, mMainServiceConnection, Context.BIND_AUTO_CREATE); - if (bindSuccess) { - mIsServiceBound = true; - LogUtils.d(TAG, "bindMainService: 绑定MainService成功"); - } else { - LogUtils.e(TAG, "bindMainService: 绑定MainService失败"); - } - } - - /** - * 解绑MainService - */ - private void unbindMainService() { - if (mIsServiceBound && mMainServiceConnection != null) { - try { - unbindService(mMainServiceConnection); - mIsServiceBound = false; - LogUtils.d(TAG, "unbindMainService: 解绑MainService成功"); - } catch (IllegalArgumentException e) { - LogUtils.w(TAG, "unbindMainService: 服务未绑定,解绑失败", e); - } - } - } + // ====================== 10. 移除 MainService 绑定/解绑工具方法(bindMainService/unbindMainService 完全删除) ====================== // ====================== 11. 菜单相关函数区 ====================== @Override @@ -586,23 +477,8 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv // ====================== 14. 内部类定义区(Java 7 规范,禁止Lambda) ====================== /** - * MainService连接类,用于传递窗口状态 + * 移除 MainServiceConnection 内部类(服务绑定相关,已删除绑定逻辑) */ - private class MainServiceConnection implements ServiceConnection { - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - LogUtils.d(TAG, "MainServiceConnection: 与MainService连接成功"); - MainService.MyBinder binder = (MainService.MyBinder) service; - // 通知MainService窗口处于活跃状态 - binder.setMainWindowDestroyed(false); - } - - @Override - public void onServiceDisconnected(ComponentName name) { - LogUtils.w(TAG, "MainServiceConnection: 与MainService连接断开"); - mIsServiceBound = false; - } - } /** * ViewPager适配器(静态内部类减少内存泄漏风险,Java7泛型完整声明) @@ -635,29 +511,7 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv } /** - * 电话状态监听器(Java7内部类规范写法) + * 移除 MyPhoneStateListener 内部类(电话状态监听相关,已删除监听逻辑) */ - private class MyPhoneStateListener extends PhoneStateListener { - @Override - public void onCallStateChanged(int state, String incomingNumber) { - super.onCallStateChanged(state, incomingNumber); - String stateDesc = ""; - switch (state) { - case TelephonyManager.CALL_STATE_IDLE: - stateDesc = "空闲"; - break; - case TelephonyManager.CALL_STATE_OFFHOOK: - stateDesc = "通话中"; - break; - case TelephonyManager.CALL_STATE_RINGING: - stateDesc = "来电(" + incomingNumber + ")"; - break; - default: - stateDesc = "未知状态(" + state + ")"; - break; - } - LogUtils.d(TAG, "onCallStateChanged: 电话状态=" + stateDesc); - } - } } diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/services/MainService.java b/contacts/src/main/java/cc/winboll/studio/contacts/services/MainService.java index b372da9..bcdad3a 100644 --- a/contacts/src/main/java/cc/winboll/studio/contacts/services/MainService.java +++ b/contacts/src/main/java/cc/winboll/studio/contacts/services/MainService.java @@ -59,7 +59,7 @@ public class MainService extends Service { private static MainService sMainServiceInstance; private static volatile TomCat sTomCatInstance; - // ====================== 成员变量区(新增主窗口销毁状态标记) ====================== + // ====================== 成员变量区 ====================== private volatile boolean mIsServiceRunning; private MainServiceBean mMainServiceBean; private MainServiceThread mMainServiceThread; @@ -70,24 +70,16 @@ public class MainService extends Service { private MainReceiver mMainReceiver; private Timer mStreamVolumeCheckTimer; private Handler mDelayHandler; - // 核心:标记主窗口是否已销毁,阻断后续无效服务启动 - private boolean mIsMainWindowDestroyed = false; - // ====================== Binder 内部类(Java 7 规范写法,新增窗口状态设置方法) ====================== + // ====================== Binder 内部类 ====================== public class MyBinder extends Binder { public MainService getService() { LogUtils.d(TAG, "MyBinder.getService: 获取 MainService 实例"); return MainService.this; } - - // 对外暴露:设置主窗口销毁状态 - public void setMainWindowDestroyed(boolean isDestroyed) { - mIsMainWindowDestroyed = isDestroyed; - LogUtils.w(TAG, "MyBinder.setMainWindowDestroyed: 主窗口销毁状态更新为 " + isDestroyed); - } } - // ====================== ServiceConnection 内部类(Java 7 匿名内部类规范) ====================== + // ====================== ServiceConnection 内部类 ====================== private class MyServiceConnection implements ServiceConnection { @Override public void onServiceConnected(ComponentName name, IBinder service) { @@ -114,8 +106,8 @@ public class MainService extends Service { mAssistantService = null; mIsBound = false; - // 新增:主窗口销毁后,不再重试绑定守护服务 - if (mMainServiceBean != null && mMainServiceBean.isEnable() && !mIsMainWindowDestroyed) { + // 服务启用则重试绑定 + if (mMainServiceBean != null && mMainServiceBean.isEnable()) { LogUtils.d(TAG, "MyServiceConnection.onServiceDisconnected: 重新唤醒并绑定守护服务"); new Handler(Looper.getMainLooper()).postDelayed(new Runnable() { @Override @@ -124,12 +116,12 @@ public class MainService extends Service { } }, RETRY_DELAY_MS); } else { - LogUtils.w(TAG, "MyServiceConnection.onServiceDisconnected: 主窗口已销毁/服务未启用,跳过重试"); + LogUtils.w(TAG, "MyServiceConnection.onServiceDisconnected: 服务未启用,跳过重试"); } } } - // ====================== 对外静态方法区(强化参数校验,添加日志) ====================== + // ====================== 对外静态方法区 ====================== public static boolean isPhoneInBoBullToon(String phone) { if (sTomCatInstance != null && phone != null && !phone.isEmpty()) { return sTomCatInstance.isPhoneBoBullToon(phone); @@ -204,10 +196,9 @@ public class MainService extends Service { startMainService(context); } - // ====================== 成员方法区(新增服务启动前置校验 + 延迟启动封装) ====================== + // ====================== 成员方法区 ====================== /** * 补充缺失的 appenMessage 方法 - * 用于接收并处理消息,支持日志打印和通过 Handler 转发到主线程 */ public void appenMessage(String message) { String msg = message == null ? "null" : message; @@ -222,17 +213,10 @@ public class MainService extends Service { } /** - * 服务启动前置校验(核心:阻断无效启动) - * @param serviceClass 待启动服务类 - * @return true=允许启动 false=禁止启动 + * 服务启动前置校验 */ private boolean canStartService(Class serviceClass) { - // 1. 主窗口已销毁 → 禁止启动 - if (mIsMainWindowDestroyed) { - LogUtils.w(TAG, "canStartService: 主窗口已销毁,禁止启动 " + serviceClass.getSimpleName()); - return false; - } - // 2. 服务未启用/已运行 → 禁止启动 + // 服务未启用/已运行 → 禁止启动 if (mMainServiceBean == null || !mMainServiceBean.isEnable()) { LogUtils.w(TAG, "canStartService: 主服务未启用,禁止启动 " + serviceClass.getSimpleName()); return false; @@ -241,7 +225,7 @@ public class MainService extends Service { LogUtils.d(TAG, "canStartService: " + serviceClass.getSimpleName() + " 已运行,跳过启动"); return false; } - // 3. Android 12+ 应用后台 → 禁止启动非核心服务 + // Android 12+ 应用后台 → 禁止启动非核心服务 if (Build.VERSION.SDK_INT >= ANDROID_12_API && !AppForegroundUtils.isAppForeground(this)) { LogUtils.w(TAG, "canStartService: Android 12+ 应用后台,禁止启动 " + serviceClass.getSimpleName()); return false; @@ -250,8 +234,7 @@ public class MainService extends Service { } /** - * 延迟启动非核心服务(降低主线程负载,避免前台服务超时) - * @param serviceClass 待启动服务类 + * 延迟启动非核心服务 */ private void delayStartNonCoreService(final Class serviceClass) { if (!canStartService(serviceClass)) { @@ -276,15 +259,15 @@ public class MainService extends Service { } /** - * 创建前台服务通知(Java 7 分步构建,强化版本兼容 + 异常防护) + * 创建前台服务通知 */ private Notification createForegroundNotification() { - // 1. 创建通知渠道(Android 8.0+ 必需,添加空指针防护) + // 1. 创建通知渠道(Android 8.0+ 必需) if (Build.VERSION.SDK_INT >= ANDROID_8_API) { NotificationChannel channel = new NotificationChannel( - FOREGROUND_CHANNEL_ID, - "拨号主服务", - NotificationManager.IMPORTANCE_LOW + FOREGROUND_CHANNEL_ID, + "拨号主服务", + NotificationManager.IMPORTANCE_LOW ); channel.setDescription("主服务后台运行,保障拨号功能正常"); channel.setSound(null, null); @@ -299,14 +282,13 @@ public class MainService extends Service { } } - // 2. 构建通知(Java 7 分步设置,禁止链式调用简化) + // 2. 构建通知 Notification.Builder builder; if (Build.VERSION.SDK_INT >= ANDROID_8_API) { builder = new Notification.Builder(this, FOREGROUND_CHANNEL_ID); } else { builder = new Notification.Builder(this); } - // 关键:确保图标资源存在,否则通知创建失败导致前台服务启动超时 builder.setSmallIcon(R.drawable.ic_launcher); builder.setContentTitle("拨号服务运行中"); builder.setContentText("正在后台保障通话监听与号码识别"); @@ -317,14 +299,14 @@ public class MainService extends Service { } /** - * 启动通话监听服务(重构:改为延迟启动非核心服务) + * 启动通话监听服务 */ private void startPhoneCallListener() { delayStartNonCoreService(CallListenerService.class); } /** - * 检查服务是否正在运行(通用工具方法,避免重复代码) + * 检查服务是否正在运行 */ private boolean isServiceRunning(Class serviceClass) { if (serviceClass == null) { @@ -346,7 +328,7 @@ public class MainService extends Service { return false; } - // ====================== Service 生命周期方法区(核心优化:优先启动前台服务) ====================== + // ====================== Service 生命周期方法区 ====================== @Override public void onCreate() { super.onCreate(); @@ -354,38 +336,16 @@ public class MainService extends Service { sMainServiceInstance = this; mIsServiceRunning = false; - // ========== 核心优化 1:优先启动前台服务,放在 onCreate 最前端,避免业务逻辑阻塞导致超时 ========== - try { - Notification foregroundNotification = createForegroundNotification(); - if (Build.VERSION.SDK_INT >= ANDROID_10_API) { - startForeground(FOREGROUND_NOTIFICATION_ID, foregroundNotification, FOREGROUND_SERVICE_TYPE_DATA_SYNC); - LogUtils.d(TAG, "onCreate: 主服务已启动为前台服务(dataSync 类型,API30+)"); - } else { - startForeground(FOREGROUND_NOTIFICATION_ID, foregroundNotification); - LogUtils.d(TAG, "onCreate: 主服务已启动为前台服务(低版本兼容)"); - } - } catch (IllegalArgumentException e) { - LogUtils.e(TAG, "onCreate: 启动前台服务失败,类型不匹配", e); - stopSelf(); - return; - } catch (Exception e) { - LogUtils.e(TAG, "onCreate: 启动前台服务异常", e); - stopSelf(); - return; - } - - // ========== 初始化核心组件 ========== + // 仅初始化核心组件 mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class); mMyServiceConnection = new MyServiceConnection(); mMainServiceHandler = new MainServiceHandler(this); - mDelayHandler = new Handler(Looper.getMainLooper()); // 初始化延迟 Handler + mDelayHandler = new Handler(Looper.getMainLooper()); // 初始化铃声音量检查定时器 initVolumeCheckTimer(); - // 启动主服务核心逻辑 - mainService(); - LogUtils.d(TAG, "===== onCreate: 主服务创建完成 ====="); + LogUtils.d(TAG, "===== onCreate: 主服务创建完成(仅初始化组件) ====="); } @Override @@ -397,97 +357,132 @@ public class MainService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { LogUtils.d(TAG, "onStartCommand: 服务被启动 | startId=" + startId); - // 主窗口销毁后,不再执行核心逻辑 - if (!mIsMainWindowDestroyed) { - mainService(); - } + mainService(); return (mMainServiceBean != null && mMainServiceBean.isEnable()) ? START_STICKY : super.onStartCommand(intent, flags, startId); } + // ====================== onDestroy:强制全量清理,不改动 Bean 配置 ====================== @Override public void onDestroy() { super.onDestroy(); - LogUtils.d(TAG, "===== onDestroy: 主服务开始销毁 ====="); + LogUtils.d(TAG, "===== onDestroy: 主服务开始销毁(强制清理所有资源) ====="); - // 释放延迟 Handler 资源 + // 1. 强制标记服务为未运行 + mIsServiceRunning = false; + + // 2. 释放延迟 Handler 资源 if (mDelayHandler != null) { mDelayHandler.removeCallbacksAndMessages(null); + mDelayHandler = null; } - // 释放定时器资源 + // 3. 释放定时器资源 cancelVolumeCheckTimer(); - // 仅配置禁用时执行资源释放逻辑 - if (mMainServiceBean != null && !mMainServiceBean.isEnable()) { - mIsServiceRunning = false; - // 解除守护服务绑定 - if (mIsBound && mMyServiceConnection != null) { - try { - unbindService(mMyServiceConnection); - LogUtils.d(TAG, "onDestroy: 解除守护服务绑定成功"); - } catch (IllegalArgumentException e) { - LogUtils.w(TAG, "onDestroy: 解除绑定失败,服务未绑定", e); - } - mIsBound = false; + // 4. 强制解除守护服务绑定 + if (mIsBound && mMyServiceConnection != null) { + try { + unbindService(mMyServiceConnection); + LogUtils.d(TAG, "onDestroy: 解除守护服务绑定成功"); + } catch (IllegalArgumentException e) { + LogUtils.w(TAG, "onDestroy: 解除绑定失败,服务未绑定", e); } - - // 注销广播接收器 - if (mMainReceiver != null) { - mMainReceiver.unregisterAction(this); - mMainReceiver = null; - LogUtils.d(TAG, "onDestroy: 广播接收器已注销"); - } - - // 停止子服务 - if (mMainServiceThread != null) { - mMainServiceThread.setIsExit(true); - mMainServiceThread = null; - } - stopService(new Intent(this, AssistantService.class)); - stopService(new Intent(this, CallListenerService.class)); + mIsBound = false; + mMyServiceConnection = null; } - // 清空静态实例,避免内存泄漏 + // 5. 强制注销广播接收器 + if (mMainReceiver != null) { + mMainReceiver.unregisterAction(this); + mMainReceiver = null; + LogUtils.d(TAG, "onDestroy: 广播接收器已注销"); + } + + // 6. 强制停止主业务线程 + if (mMainServiceThread != null) { + mMainServiceThread.setIsExit(true); + mMainServiceThread = null; + } + + // 7. 强制停止所有子服务 + stopService(new Intent(this, AssistantService.class)); + stopService(new Intent(this, CallListenerService.class)); + LogUtils.d(TAG, "onDestroy: 所有子服务已强制停止"); + + // 8. 清空静态实例,避免内存泄漏(不改动 Bean 配置) sMainServiceInstance = null; sTomCatInstance = null; - LogUtils.d(TAG, "===== onDestroy: 主服务销毁完成 ====="); + mMainServiceHandler = null; + mAssistantService = null; + mMainServiceBean = null; + + LogUtils.d(TAG, "===== onDestroy: 主服务销毁完成(资源全清理,Bean 配置无改动) ====="); } - // ====================== 核心业务逻辑方法区 ====================== + // ====================== 核心业务逻辑:优先判断运行状态 → 再校验配置启用状态 ====================== private void mainService() { LogUtils.d(TAG, "mainService: 执行核心业务逻辑"); - // 重新加载配置,确保使用最新状态 - mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class); - if (mMainServiceBean == null || !mMainServiceBean.isEnable() || mIsServiceRunning) { - LogUtils.d(TAG, "mainService: 无需启动 | 配置启用=" + (mMainServiceBean != null && mMainServiceBean.isEnable()) + " | 服务运行中=" + mIsServiceRunning); + + // 第一步:优先判断服务是否已运行,已运行则直接退出(不做任何动作) + if (mIsServiceRunning) { + LogUtils.d(TAG, "mainService: 服务已处于运行状态,直接退出"); return; } - // 标记服务为运行状态 - mIsServiceRunning = true; - LogUtils.i(TAG, "mainService: 主服务开始运行"); + // 第二步:加载最新配置,校验服务是否启用(未启用则退出) + mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class); + if (mMainServiceBean == null || !mMainServiceBean.isEnable()) { + LogUtils.w(TAG, "mainService: 服务配置未启用/配置加载失败,退出启动流程"); + return; + } - // 1. 绑定守护服务(核心服务,立即启动) + // 第三步:配置启用且服务未运行,执行启动流程 + mIsServiceRunning = true; + LogUtils.i(TAG, "mainService: 服务未运行且配置已启用,开始启动核心流程"); + + // 1. 启动前台服务(优先执行,避免超时) + try { + Notification foregroundNotification = createForegroundNotification(); + if (Build.VERSION.SDK_INT >= ANDROID_10_API) { + startForeground(FOREGROUND_NOTIFICATION_ID, foregroundNotification, FOREGROUND_SERVICE_TYPE_DATA_SYNC); + LogUtils.d(TAG, "mainService: 主服务已启动为前台服务(dataSync 类型,API30+)"); + } else { + startForeground(FOREGROUND_NOTIFICATION_ID, foregroundNotification); + LogUtils.d(TAG, "mainService: 主服务已启动为前台服务(低版本兼容)"); + } + } catch (IllegalArgumentException e) { + LogUtils.e(TAG, "mainService: 启动前台服务失败,类型不匹配", e); + mIsServiceRunning = false; + stopSelf(); + return; + } catch (Exception e) { + LogUtils.e(TAG, "mainService: 启动前台服务异常", e); + mIsServiceRunning = false; + stopSelf(); + return; + } + + // 2. 绑定守护服务 wakeupAndBindAssistant(); - // 2. 初始化业务组件 + // 3. 初始化业务组件 initTomCat(); initMainReceiver(); Rules.getInstance(this).loadRules(); LogUtils.d(TAG, "mainService: 黑白名单规则已加载"); - // 3. 延迟启动通话监听服务(非核心服务,降低主线程负载) + // 4. 启动电话监听服务 startPhoneCallListener(); - // 4. 启动主业务线程 + // 5. 启动主业务线程 mMainServiceThread = MainServiceThread.getInstance(this, mMainServiceHandler); mMainServiceThread.start(); - LogUtils.i(TAG, "mainService: 主业务线程已启动"); + LogUtils.i(TAG, "mainService: 核心流程启动完成,主服务正常运行"); } private void wakeupAndBindAssistant() { - if (mMyServiceConnection == null || mIsMainWindowDestroyed) { - LogUtils.e(TAG, "wakeupAndBindAssistant: 初始化失败/主窗口已销毁,绑定失败"); + if (mMyServiceConnection == null) { + LogUtils.e(TAG, "wakeupAndBindAssistant: 初始化失败,绑定失败"); return; } Intent intent = new Intent(this, AssistantService.class); @@ -529,7 +524,7 @@ public class MainService extends Service { LogUtils.d(TAG, "checkAndRestoreRingerVolume: 铃音配置未存在,已初始化默认配置"); } - // 检查并恢复音量,添加权限异常捕获 + // 检查并恢复音量 try { int currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_RING); int configVolume = ringTongBean.getStreamVolume();