20251213_104727_568服务启动模块修改。
This commit is contained in:
@@ -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&豆包大模型<zhangsken@qq.com>
|
||||
* @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<Fragment> fragmentList;
|
||||
private List<String> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user