20251213_104727_568服务启动模块修改。

This commit is contained in:
2025-12-13 10:48:00 +08:00
parent b6a820b281
commit 61a20f6811
2 changed files with 129 additions and 280 deletions

View File

@@ -4,21 +4,16 @@ import android.Manifest;
import android.app.Activity; import android.app.Activity;
import android.app.ActivityManager; import android.app.ActivityManager;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.Color; import android.graphics.Color;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.IBinder;
import android.os.Looper; import android.os.Looper;
import android.telecom.TelecomManager; import android.telecom.TelecomManager;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; 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.fragments.LogFragment;
import cc.winboll.studio.contacts.model.MainServiceBean; import cc.winboll.studio.contacts.model.MainServiceBean;
import cc.winboll.studio.contacts.services.MainService; 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.utils.PermissionUtils;
import cc.winboll.studio.contacts.views.DunTemperatureView; import cc.winboll.studio.contacts.views.DunTemperatureView;
import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity; import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity;
@@ -57,7 +51,7 @@ import java.util.List;
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com> * @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/08/30 14:32 * @Date 2025/08/30 14:32
* @Describe Contacts 主窗口(完全适配 API 30 + Java 7 语法) * @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 { 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 DIALER_REQUEST_CODE = 1;
private static final int REQUEST_REQUIRED_PERMISSIONS = 1002; private static final int REQUEST_REQUIRED_PERMISSIONS = 1002;
private static final int REQUEST_OVERLAY_PERMISSION = 1003; private static final int REQUEST_OVERLAY_PERMISSION = 1003;
private static final int REQUEST_CALL_SCREENING_PERMISSION = 1004;
// API版本硬编码常量Java 7兼容杜绝Build.VERSION_CODES高版本引用 // API版本硬编码常量Java 7兼容杜绝Build.VERSION_CODES高版本引用
private static final int ANDROID_6_API = 23; private static final int ANDROID_6_API = 23;
@@ -98,13 +91,8 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv
// ====================== 5. 业务逻辑成员区 ====================== // ====================== 5. 业务逻辑成员区 ======================
private MainServiceBean mMainServiceBean; private MainServiceBean mMainServiceBean;
private int currentPoint = 0; private int currentPoint = 0;
private TelephonyManager telephonyManager;
private MyPhoneStateListener phoneStateListener;
private List<Fragment> fragmentList; private List<Fragment> fragmentList;
private List<String> tabTitleList; private List<String> tabTitleList;
// 新增ServiceConnection用于与MainService绑定并传递窗口状态
private MainServiceConnection mMainServiceConnection;
private boolean mIsServiceBound = false;
// ====================== 6. 接口实现区 ====================== // ====================== 6. 接口实现区 ======================
@Override @Override
@@ -124,9 +112,6 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv
LogUtils.d(TAG, "===== onCreate: 主Activity开始创建 ====="); LogUtils.d(TAG, "===== onCreate: 主Activity开始创建 =====");
_MainActivity = this; _MainActivity = this;
// 初始化ServiceConnection
mMainServiceConnection = new MainServiceConnection();
// 直接初始化UI原权限检查逻辑注释保留按需启用 // 直接初始化UI原权限检查逻辑注释保留按需启用
initUIAndLogic(savedInstanceState); initUIAndLogic(savedInstanceState);
LogUtils.d(TAG, "===== onCreate: 主Activity创建流程结束 ====="); LogUtils.d(TAG, "===== onCreate: 主Activity创建流程结束 =====");
@@ -145,15 +130,13 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv
mADsBannerView.resumeADs(MainActivity.this); mADsBannerView.resumeADs(MainActivity.this);
LogUtils.d(TAG, "onResume: 广告栏资源已恢复"); LogUtils.d(TAG, "onResume: 广告栏资源已恢复");
} }
// 绑定MainService,用于传递窗口状态 // 移除 MainService 绑定逻辑
bindMainService();
} }
@Override @Override
protected void onPause() { protected void onPause() {
super.onPause(); super.onPause();
// 解绑MainService,避免内存泄漏 // 移除 MainService 解绑逻辑
unbindMainService();
} }
@Override @Override
@@ -165,28 +148,8 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv
mADsBannerView.releaseAdResources(); mADsBannerView.releaseAdResources();
LogUtils.d(TAG, "onDestroy: 广告栏资源已释放"); LogUtils.d(TAG, "onDestroy: 广告栏资源已释放");
} }
// 移除电话状态监听,防止内存泄漏 // 移除电话状态监听释放逻辑(已删除监听初始化,无需释放)
if (telephonyManager != null && phoneStateListener != null) { // 移除 MainService 解绑及状态传递逻辑
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);
LogUtils.d(TAG, "===== onDestroy: 主Activity销毁完成 ====="); LogUtils.d(TAG, "===== onDestroy: 主Activity销毁完成 =====");
} }
@@ -227,9 +190,7 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv
case REQUEST_OVERLAY_PERMISSION: case REQUEST_OVERLAY_PERMISSION:
handleOverlayPermissionResult(); handleOverlayPermissionResult();
break; break;
case REQUEST_CALL_SCREENING_PERMISSION: // 移除 通话筛选权限回调(REQUEST_CALL_SCREENING_PERMISSION)分支
handleCallScreeningPermissionResult();
break;
default: default:
LogUtils.w(TAG, "onActivityResult: 未知requestCode=" + requestCode); LogUtils.w(TAG, "onActivityResult: 未知requestCode=" + requestCode);
break; break;
@@ -242,7 +203,9 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv
private void handleOverlayPermissionResult() { private void handleOverlayPermissionResult() {
if (PermissionUtils.isOverlayPermissionGranted(this)) { if (PermissionUtils.isOverlayPermissionGranted(this)) {
LogUtils.d(TAG, "handleOverlayPermissionResult: 悬浮窗权限申请成功"); LogUtils.d(TAG, "handleOverlayPermissionResult: 悬浮窗权限申请成功");
checkAndRequestRemainingPermissions(); // 移除 通话筛选权限检查(直接完成权限流程)
LogUtils.d(TAG, "handleOverlayPermissionResult: 所有权限已授予");
initUIAndLogic(null);
} else { } else {
LogUtils.e(TAG, "handleOverlayPermissionResult: 悬浮窗权限申请失败"); LogUtils.e(TAG, "handleOverlayPermissionResult: 悬浮窗权限申请失败");
showPermissionDeniedDialogAndExit("应用需要悬浮窗权限才能展示来电弹窗,请授予后重新打开应用。"); 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() { private void checkAndRequestRemainingPermissions() {
if (!PermissionUtils.isOverlayPermissionGranted(this)) { if (!PermissionUtils.isOverlayPermissionGranted(this)) {
LogUtils.d(TAG, "checkAndRequestRemainingPermissions: 悬浮窗权限未授予,跳转设置页"); LogUtils.d(TAG, "checkAndRequestRemainingPermissions: 悬浮窗权限未授予,跳转设置页");
PermissionUtils.requestOverlayPermission(this, REQUEST_OVERLAY_PERMISSION); 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 { } else {
LogUtils.d(TAG, "checkAndRequestRemainingPermissions: 所有权限已授予"); LogUtils.d(TAG, "checkAndRequestRemainingPermissions: 所有权限已授予");
initUIAndLogic(null); initUIAndLogic(null);
@@ -336,13 +283,11 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv
mADsBannerView = (ADsBannerView) findViewById(R.id.adsbanner); mADsBannerView = (ADsBannerView) findViewById(R.id.adsbanner);
LogUtils.d(TAG, "initUIAndLogic: 广告栏控件初始化完成"); LogUtils.d(TAG, "initUIAndLogic: 广告栏控件初始化完成");
// 4. 主服务初始化 // 4. 主服务初始化(保留启动逻辑,移除绑定相关)
initMainService(); initMainService();
LogUtils.d(TAG, "initUIAndLogic: 主服务初始化完成"); LogUtils.d(TAG, "initUIAndLogic: 主服务初始化完成");
// 5. 电话状态监听初始化 // 5. 移除 电话状态监听初始化逻辑initPhoneStateListener() 调用删除)
initPhoneStateListener();
LogUtils.d(TAG, "initUIAndLogic: 电话状态监听器初始化完成");
// 左边盾值视图初始化Java7分步写法禁止链式调用 // 左边盾值视图初始化Java7分步写法禁止链式调用
DunTemperatureView tempViewLeft = (DunTemperatureView) findViewById(R.id.dun_temp_view_left); 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() { private void initMainService() {
LogUtils.d(TAG, "initMainService: 开始初始化主服务配置"); LogUtils.d(TAG, "initMainService: 开始初始化主服务配置");
@@ -414,13 +359,13 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv
MainServiceBean.saveBean(this, mMainServiceBean); MainServiceBean.saveBean(this, mMainServiceBean);
} }
// 检查服务状态并启动 // 检查服务状态并启动(使用静态方法,无绑定依赖)
if (mMainServiceBean.isEnable() && !isServiceRunning(MainService.class)) { if (mMainServiceBean.isEnable() && !isServiceRunning(MainService.class)) {
LogUtils.d(TAG, "initMainService: 主服务已启用且未运行延迟1秒启动"); LogUtils.d(TAG, "initMainService: 主服务已启用且未运行延迟1秒启动");
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() { new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override @Override
public void run() { public void run() {
MainService.startMainService(MainActivity.this); MainService.startMainServiceAndSaveStatus(MainActivity.this);
LogUtils.d(TAG, "initMainService: 主服务启动任务执行"); LogUtils.d(TAG, "initMainService: 主服务启动任务执行");
} }
}, 1000); }, 1000);
@@ -430,61 +375,7 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv
} }
} }
/** // ====================== 10. 移除 MainService 绑定/解绑工具方法bindMainService/unbindMainService 完全删除) ======================
* 初始化电话状态监听与通话筛选服务适配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);
}
}
}
// ====================== 11. 菜单相关函数区 ====================== // ====================== 11. 菜单相关函数区 ======================
@Override @Override
@@ -586,23 +477,8 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv
// ====================== 14. 内部类定义区Java 7 规范禁止Lambda ====================== // ====================== 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泛型完整声明 * 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);
}
}
} }

View File

@@ -59,7 +59,7 @@ public class MainService extends Service {
private static MainService sMainServiceInstance; private static MainService sMainServiceInstance;
private static volatile TomCat sTomCatInstance; private static volatile TomCat sTomCatInstance;
// ====================== 成员变量区(新增主窗口销毁状态标记) ====================== // ====================== 成员变量区 ======================
private volatile boolean mIsServiceRunning; private volatile boolean mIsServiceRunning;
private MainServiceBean mMainServiceBean; private MainServiceBean mMainServiceBean;
private MainServiceThread mMainServiceThread; private MainServiceThread mMainServiceThread;
@@ -70,24 +70,16 @@ public class MainService extends Service {
private MainReceiver mMainReceiver; private MainReceiver mMainReceiver;
private Timer mStreamVolumeCheckTimer; private Timer mStreamVolumeCheckTimer;
private Handler mDelayHandler; private Handler mDelayHandler;
// 核心:标记主窗口是否已销毁,阻断后续无效服务启动
private boolean mIsMainWindowDestroyed = false;
// ====================== Binder 内部类Java 7 规范写法,新增窗口状态设置方法) ====================== // ====================== Binder 内部类 ======================
public class MyBinder extends Binder { public class MyBinder extends Binder {
public MainService getService() { public MainService getService() {
LogUtils.d(TAG, "MyBinder.getService: 获取 MainService 实例"); LogUtils.d(TAG, "MyBinder.getService: 获取 MainService 实例");
return MainService.this; 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 { private class MyServiceConnection implements ServiceConnection {
@Override @Override
public void onServiceConnected(ComponentName name, IBinder service) { public void onServiceConnected(ComponentName name, IBinder service) {
@@ -114,8 +106,8 @@ public class MainService extends Service {
mAssistantService = null; mAssistantService = null;
mIsBound = false; mIsBound = false;
// 新增:主窗口销毁后,不再重试绑定守护服务 // 服务启用则重试绑定
if (mMainServiceBean != null && mMainServiceBean.isEnable() && !mIsMainWindowDestroyed) { if (mMainServiceBean != null && mMainServiceBean.isEnable()) {
LogUtils.d(TAG, "MyServiceConnection.onServiceDisconnected: 重新唤醒并绑定守护服务"); LogUtils.d(TAG, "MyServiceConnection.onServiceDisconnected: 重新唤醒并绑定守护服务");
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() { new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override @Override
@@ -124,12 +116,12 @@ public class MainService extends Service {
} }
}, RETRY_DELAY_MS); }, RETRY_DELAY_MS);
} else { } else {
LogUtils.w(TAG, "MyServiceConnection.onServiceDisconnected: 主窗口已销毁/服务未启用,跳过重试"); LogUtils.w(TAG, "MyServiceConnection.onServiceDisconnected: 服务未启用,跳过重试");
} }
} }
} }
// ====================== 对外静态方法区(强化参数校验,添加日志) ====================== // ====================== 对外静态方法区 ======================
public static boolean isPhoneInBoBullToon(String phone) { public static boolean isPhoneInBoBullToon(String phone) {
if (sTomCatInstance != null && phone != null && !phone.isEmpty()) { if (sTomCatInstance != null && phone != null && !phone.isEmpty()) {
return sTomCatInstance.isPhoneBoBullToon(phone); return sTomCatInstance.isPhoneBoBullToon(phone);
@@ -204,10 +196,9 @@ public class MainService extends Service {
startMainService(context); startMainService(context);
} }
// ====================== 成员方法区(新增服务启动前置校验 + 延迟启动封装) ====================== // ====================== 成员方法区 ======================
/** /**
* 补充缺失的 appenMessage 方法 * 补充缺失的 appenMessage 方法
* 用于接收并处理消息,支持日志打印和通过 Handler 转发到主线程
*/ */
public void appenMessage(String message) { public void appenMessage(String message) {
String msg = message == null ? "null" : 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) { private boolean canStartService(Class<?> serviceClass) {
// 1. 主窗口已销毁 → 禁止启动 // 服务未启用/已运行 → 禁止启动
if (mIsMainWindowDestroyed) {
LogUtils.w(TAG, "canStartService: 主窗口已销毁,禁止启动 " + serviceClass.getSimpleName());
return false;
}
// 2. 服务未启用/已运行 → 禁止启动
if (mMainServiceBean == null || !mMainServiceBean.isEnable()) { if (mMainServiceBean == null || !mMainServiceBean.isEnable()) {
LogUtils.w(TAG, "canStartService: 主服务未启用,禁止启动 " + serviceClass.getSimpleName()); LogUtils.w(TAG, "canStartService: 主服务未启用,禁止启动 " + serviceClass.getSimpleName());
return false; return false;
@@ -241,7 +225,7 @@ public class MainService extends Service {
LogUtils.d(TAG, "canStartService: " + serviceClass.getSimpleName() + " 已运行,跳过启动"); LogUtils.d(TAG, "canStartService: " + serviceClass.getSimpleName() + " 已运行,跳过启动");
return false; return false;
} }
// 3. Android 12+ 应用后台 → 禁止启动非核心服务 // Android 12+ 应用后台 → 禁止启动非核心服务
if (Build.VERSION.SDK_INT >= ANDROID_12_API && !AppForegroundUtils.isAppForeground(this)) { if (Build.VERSION.SDK_INT >= ANDROID_12_API && !AppForegroundUtils.isAppForeground(this)) {
LogUtils.w(TAG, "canStartService: Android 12+ 应用后台,禁止启动 " + serviceClass.getSimpleName()); LogUtils.w(TAG, "canStartService: Android 12+ 应用后台,禁止启动 " + serviceClass.getSimpleName());
return false; return false;
@@ -250,8 +234,7 @@ public class MainService extends Service {
} }
/** /**
* 延迟启动非核心服务(降低主线程负载,避免前台服务超时) * 延迟启动非核心服务
* @param serviceClass 待启动服务类
*/ */
private void delayStartNonCoreService(final Class<?> serviceClass) { private void delayStartNonCoreService(final Class<?> serviceClass) {
if (!canStartService(serviceClass)) { if (!canStartService(serviceClass)) {
@@ -276,15 +259,15 @@ public class MainService extends Service {
} }
/** /**
* 创建前台服务通知Java 7 分步构建,强化版本兼容 + 异常防护) * 创建前台服务通知
*/ */
private Notification createForegroundNotification() { private Notification createForegroundNotification() {
// 1. 创建通知渠道Android 8.0+ 必需,添加空指针防护 // 1. 创建通知渠道Android 8.0+ 必需)
if (Build.VERSION.SDK_INT >= ANDROID_8_API) { if (Build.VERSION.SDK_INT >= ANDROID_8_API) {
NotificationChannel channel = new NotificationChannel( NotificationChannel channel = new NotificationChannel(
FOREGROUND_CHANNEL_ID, FOREGROUND_CHANNEL_ID,
"拨号主服务", "拨号主服务",
NotificationManager.IMPORTANCE_LOW NotificationManager.IMPORTANCE_LOW
); );
channel.setDescription("主服务后台运行,保障拨号功能正常"); channel.setDescription("主服务后台运行,保障拨号功能正常");
channel.setSound(null, null); channel.setSound(null, null);
@@ -299,14 +282,13 @@ public class MainService extends Service {
} }
} }
// 2. 构建通知Java 7 分步设置,禁止链式调用简化) // 2. 构建通知
Notification.Builder builder; Notification.Builder builder;
if (Build.VERSION.SDK_INT >= ANDROID_8_API) { if (Build.VERSION.SDK_INT >= ANDROID_8_API) {
builder = new Notification.Builder(this, FOREGROUND_CHANNEL_ID); builder = new Notification.Builder(this, FOREGROUND_CHANNEL_ID);
} else { } else {
builder = new Notification.Builder(this); builder = new Notification.Builder(this);
} }
// 关键:确保图标资源存在,否则通知创建失败导致前台服务启动超时
builder.setSmallIcon(R.drawable.ic_launcher); builder.setSmallIcon(R.drawable.ic_launcher);
builder.setContentTitle("拨号服务运行中"); builder.setContentTitle("拨号服务运行中");
builder.setContentText("正在后台保障通话监听与号码识别"); builder.setContentText("正在后台保障通话监听与号码识别");
@@ -317,14 +299,14 @@ public class MainService extends Service {
} }
/** /**
* 启动通话监听服务(重构:改为延迟启动非核心服务) * 启动通话监听服务
*/ */
private void startPhoneCallListener() { private void startPhoneCallListener() {
delayStartNonCoreService(CallListenerService.class); delayStartNonCoreService(CallListenerService.class);
} }
/** /**
* 检查服务是否正在运行(通用工具方法,避免重复代码) * 检查服务是否正在运行
*/ */
private boolean isServiceRunning(Class<?> serviceClass) { private boolean isServiceRunning(Class<?> serviceClass) {
if (serviceClass == null) { if (serviceClass == null) {
@@ -346,7 +328,7 @@ public class MainService extends Service {
return false; return false;
} }
// ====================== Service 生命周期方法区(核心优化:优先启动前台服务) ====================== // ====================== Service 生命周期方法区 ======================
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
@@ -354,38 +336,16 @@ public class MainService extends Service {
sMainServiceInstance = this; sMainServiceInstance = this;
mIsServiceRunning = false; 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); mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class);
mMyServiceConnection = new MyServiceConnection(); mMyServiceConnection = new MyServiceConnection();
mMainServiceHandler = new MainServiceHandler(this); mMainServiceHandler = new MainServiceHandler(this);
mDelayHandler = new Handler(Looper.getMainLooper()); // 初始化延迟 Handler mDelayHandler = new Handler(Looper.getMainLooper());
// 初始化铃声音量检查定时器 // 初始化铃声音量检查定时器
initVolumeCheckTimer(); initVolumeCheckTimer();
// 启动主服务核心逻辑 LogUtils.d(TAG, "===== onCreate: 主服务创建完成(仅初始化组件) =====");
mainService();
LogUtils.d(TAG, "===== onCreate: 主服务创建完成 =====");
} }
@Override @Override
@@ -397,97 +357,132 @@ public class MainService extends Service {
@Override @Override
public int onStartCommand(Intent intent, int flags, int startId) { public int onStartCommand(Intent intent, int flags, int startId) {
LogUtils.d(TAG, "onStartCommand: 服务被启动 | startId=" + startId); LogUtils.d(TAG, "onStartCommand: 服务被启动 | startId=" + startId);
// 主窗口销毁后,不再执行核心逻辑 mainService();
if (!mIsMainWindowDestroyed) {
mainService();
}
return (mMainServiceBean != null && mMainServiceBean.isEnable()) ? START_STICKY : super.onStartCommand(intent, flags, startId); return (mMainServiceBean != null && mMainServiceBean.isEnable()) ? START_STICKY : super.onStartCommand(intent, flags, startId);
} }
// ====================== onDestroy强制全量清理不改动 Bean 配置 ======================
@Override @Override
public void onDestroy() { public void onDestroy() {
super.onDestroy(); super.onDestroy();
LogUtils.d(TAG, "===== onDestroy: 主服务开始销毁 ====="); LogUtils.d(TAG, "===== onDestroy: 主服务开始销毁(强制清理所有资源) =====");
// 释放延迟 Handler 资源 // 1. 强制标记服务为未运行
mIsServiceRunning = false;
// 2. 释放延迟 Handler 资源
if (mDelayHandler != null) { if (mDelayHandler != null) {
mDelayHandler.removeCallbacksAndMessages(null); mDelayHandler.removeCallbacksAndMessages(null);
mDelayHandler = null;
} }
// 释放定时器资源 // 3. 释放定时器资源
cancelVolumeCheckTimer(); cancelVolumeCheckTimer();
// 仅配置禁用时执行资源释放逻辑 // 4. 强制解除守护服务绑定
if (mMainServiceBean != null && !mMainServiceBean.isEnable()) { if (mIsBound && mMyServiceConnection != null) {
mIsServiceRunning = false; try {
// 解除守护服务绑定 unbindService(mMyServiceConnection);
if (mIsBound && mMyServiceConnection != null) { LogUtils.d(TAG, "onDestroy: 解除守护服务绑定成功");
try { } catch (IllegalArgumentException e) {
unbindService(mMyServiceConnection); LogUtils.w(TAG, "onDestroy: 解除绑定失败,服务未绑定", e);
LogUtils.d(TAG, "onDestroy: 解除守护服务绑定成功");
} catch (IllegalArgumentException e) {
LogUtils.w(TAG, "onDestroy: 解除绑定失败,服务未绑定", e);
}
mIsBound = false;
} }
mIsBound = false;
// 注销广播接收器 mMyServiceConnection = null;
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));
} }
// 清空静态实例,避免内存泄漏 // 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; sMainServiceInstance = null;
sTomCatInstance = null; sTomCatInstance = null;
LogUtils.d(TAG, "===== onDestroy: 主服务销毁完成 ====="); mMainServiceHandler = null;
mAssistantService = null;
mMainServiceBean = null;
LogUtils.d(TAG, "===== onDestroy: 主服务销毁完成资源全清理Bean 配置无改动) =====");
} }
// ====================== 核心业务逻辑方法区 ====================== // ====================== 核心业务逻辑:优先判断运行状态 → 再校验配置启用状态 ======================
private void mainService() { private void mainService() {
LogUtils.d(TAG, "mainService: 执行核心业务逻辑"); LogUtils.d(TAG, "mainService: 执行核心业务逻辑");
// 重新加载配置,确保使用最新状态
mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class); // 第一步:优先判断服务是否已运行,已运行则直接退出(不做任何动作)
if (mMainServiceBean == null || !mMainServiceBean.isEnable() || mIsServiceRunning) { if (mIsServiceRunning) {
LogUtils.d(TAG, "mainService: 无需启动 | 配置启用=" + (mMainServiceBean != null && mMainServiceBean.isEnable()) + " | 服务运行中=" + mIsServiceRunning); LogUtils.d(TAG, "mainService: 服务已处于运行状态,直接退出");
return; return;
} }
// 标记服务为运行状态 // 第二步:加载最新配置,校验服务是否启用(未启用则退出)
mIsServiceRunning = true; mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class);
LogUtils.i(TAG, "mainService: 主服务开始运行"); 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(); wakeupAndBindAssistant();
// 2. 初始化业务组件 // 3. 初始化业务组件
initTomCat(); initTomCat();
initMainReceiver(); initMainReceiver();
Rules.getInstance(this).loadRules(); Rules.getInstance(this).loadRules();
LogUtils.d(TAG, "mainService: 黑白名单规则已加载"); LogUtils.d(TAG, "mainService: 黑白名单规则已加载");
// 3. 延迟启动话监听服务(非核心服务,降低主线程负载) // 4. 启动话监听服务
startPhoneCallListener(); startPhoneCallListener();
// 4. 启动主业务线程 // 5. 启动主业务线程
mMainServiceThread = MainServiceThread.getInstance(this, mMainServiceHandler); mMainServiceThread = MainServiceThread.getInstance(this, mMainServiceHandler);
mMainServiceThread.start(); mMainServiceThread.start();
LogUtils.i(TAG, "mainService: 主业务线程已启动"); LogUtils.i(TAG, "mainService: 核心流程启动完成,主服务正常运行");
} }
private void wakeupAndBindAssistant() { private void wakeupAndBindAssistant() {
if (mMyServiceConnection == null || mIsMainWindowDestroyed) { if (mMyServiceConnection == null) {
LogUtils.e(TAG, "wakeupAndBindAssistant: 初始化失败/主窗口已销毁,绑定失败"); LogUtils.e(TAG, "wakeupAndBindAssistant: 初始化失败,绑定失败");
return; return;
} }
Intent intent = new Intent(this, AssistantService.class); Intent intent = new Intent(this, AssistantService.class);
@@ -529,7 +524,7 @@ public class MainService extends Service {
LogUtils.d(TAG, "checkAndRestoreRingerVolume: 铃音配置未存在,已初始化默认配置"); LogUtils.d(TAG, "checkAndRestoreRingerVolume: 铃音配置未存在,已初始化默认配置");
} }
// 检查并恢复音量,添加权限异常捕获 // 检查并恢复音量
try { try {
int currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_RING); int currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_RING);
int configVolume = ringTongBean.getStreamVolume(); int configVolume = ringTongBean.getStreamVolume();