diff --git a/contacts/build.properties b/contacts/build.properties index 2dc79fa..9a88b1f 100644 --- a/contacts/build.properties +++ b/contacts/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Sat Dec 13 03:37:48 GMT 2025 +#Sat Dec 13 05:41:14 GMT 2025 stageCount=1 libraryProject= baseVersion=15.12 publishVersion=15.12.0 -buildCount=81 +buildCount=99 baseBetaVersion=15.12.1 diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/App.java b/contacts/src/main/java/cc/winboll/studio/contacts/App.java index 0b3576c..05e51ac 100644 --- a/contacts/src/main/java/cc/winboll/studio/contacts/App.java +++ b/contacts/src/main/java/cc/winboll/studio/contacts/App.java @@ -18,11 +18,16 @@ public class App extends GlobalApplication { super.onCreate(); // 设置应用调试标志 setIsDebugging(BuildConfig.DEBUG); - + // 初始化窗口管理类 WinBoLLActivityManager.init(this); // 初始化 Toast 框架 ToastUtils.init(this); } + @Override + public void onTerminate() { + super.onTerminate(); + ToastUtils.release(); + } } 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 154ae8b..b997cf5 100644 --- a/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java +++ b/contacts/src/main/java/cc/winboll/studio/contacts/MainActivity.java @@ -32,6 +32,8 @@ import cc.winboll.studio.contacts.dun.Rules; import cc.winboll.studio.contacts.fragments.CallLogFragment; 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.utils.PermissionUtils; import cc.winboll.studio.contacts.views.DunTemperatureView; import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity; @@ -111,6 +113,17 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv // 直接初始化UI(原权限检查逻辑注释保留,按需启用) initUIAndLogic(savedInstanceState); + + MainServiceBean mainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class); + if (mainServiceBean != null && mainServiceBean.isEnable()) { + Intent intent = new Intent(this, MainService.class); + // 根据应用前后台状态选择启动方式(Android 12+ 后台用 startForegroundService) + if (Build.VERSION.SDK_INT >= 31) { + startForegroundService(intent); + } else { + startService(intent); + } + } LogUtils.d(TAG, "===== onCreate: 主Activity创建流程结束 ====="); } diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/phonecallui/PhoneCallService.java b/contacts/src/main/java/cc/winboll/studio/contacts/phonecallui/PhoneCallService.java index 54c6101..e29a9dd 100644 --- a/contacts/src/main/java/cc/winboll/studio/contacts/phonecallui/PhoneCallService.java +++ b/contacts/src/main/java/cc/winboll/studio/contacts/phonecallui/PhoneCallService.java @@ -1,49 +1,32 @@ package cc.winboll.studio.contacts.phonecallui; -import android.content.ContentResolver; -import android.database.Cursor; import android.media.AudioManager; -import android.media.MediaRecorder; -import android.net.Uri; -import android.os.Build; -import android.provider.CallLog; import android.telecom.Call; import android.telecom.InCallService; -import android.telephony.TelephonyManager; - import cc.winboll.studio.contacts.ActivityStack; -import cc.winboll.studio.contacts.model.RingTongBean; import cc.winboll.studio.contacts.dun.Rules; import cc.winboll.studio.contacts.fragments.CallLogFragment; +import cc.winboll.studio.contacts.model.RingTongBean; import cc.winboll.studio.libappbase.LogUtils; -import java.io.File; -import java.io.IOException; - /** * @Author aJIEw, ZhanGSKen&豆包大模型 * @Date 2025/02/13 06:58:04 - * @Describe 通话状态监听服务(需 Android 6.0+),负责通话状态回调、录音、铃音控制及黑白名单校验 + * @Describe 通话状态监听服务(需 Android 6.0+),负责通话状态回调、铃音控制及黑白名单校验 * @see PhoneCallActivity * @see android.telecom.InCallService */ public class PhoneCallService extends InCallService { // ====================== 常量定义区 ====================== public static final String TAG = "PhoneCallService"; - // 强制指定正确常量值,彻底解决冲突 - // TelephonyManager 通话状态 - //private static final int CALL_STATE_OFFHOOK = TelephonyManager.CALL_STATE_OFFHOOK; // 固定值=2 - //private static final int CALL_STATE_IDLE = TelephonyManager.CALL_STATE_IDLE; // 固定值=0 - //private static final int CALL_STATE_RINGING_TELE = TelephonyManager.CALL_STATE_RINGING; // 固定值=1 - // Call 通话状态 - private static final int CALL_STATE_IDLE = Call.STATE_NEW; - private static final int CALL_STATE_RINGING = Call.STATE_RINGING; //正确值=1 - private static final int CALL_STATE_CONNECTING = Call.STATE_CONNECTING; //正确值=3 - private static final int CALL_STATE_ACTIVE = Call.STATE_ACTIVE; //正确值=2 - private static final int CALL_STATE_DISCONNECTED = Call.STATE_DISCONNECTED; //正确值=4 + // Call 通话状态(固定正确值,避免冲突) + private static final int CALL_STATE_IDLE = Call.STATE_NEW; + private static final int CALL_STATE_RINGING = Call.STATE_RINGING; // 正确值=1 + private static final int CALL_STATE_CONNECTING = Call.STATE_CONNECTING; // 正确值=3 + private static final int CALL_STATE_ACTIVE = Call.STATE_ACTIVE; // 正确值=2 + private static final int CALL_STATE_DISCONNECTED = Call.STATE_DISCONNECTED; // 正确值=4 // ====================== 成员变量区 ====================== - private MediaRecorder mMediaRecorder; private Call.Callback mCallCallback; // ====================== 内部枚举类 ====================== @@ -101,12 +84,11 @@ public class PhoneCallService extends InCallService { @Override public void onDestroy() { super.onDestroy(); - releaseRecorder(); CallLogFragment.updateCallLogFragment(); LogUtils.d(TAG, "onDestroy: 通话服务已销毁,资源已释放"); } - // ====================== 核心修复:通话状态回调 ====================== + // ====================== 核心:通话状态回调 ====================== private void initCallCallback() { mCallCallback = new Call.Callback() { @Override @@ -115,29 +97,24 @@ public class PhoneCallService extends InCallService { LogUtils.d(TAG, "onStateChanged: 状态变更 | 状态码=" + state + " | 描述=" + getCallStateDesc(state)); switch (state) { - // 仅合并值为2的两个状态,其他状态独立分支 + // 通话活跃状态(仅监听,无录音) case CALL_STATE_ACTIVE: - //case CALL_STATE_OFFHOOK: - long callId = getCurrentCallId(); - if (callId != -1) { - LogUtils.d(TAG, "onStateChanged: 通话接通/活跃,启动录音 | 通话ID=" + callId); - startRecording(callId); - } else { - LogUtils.w(TAG, "onStateChanged: 未获取到通话ID,无法录音"); - } + LogUtils.d(TAG, "onStateChanged: 通话已接通/活跃"); break; - // 状态码1独立分支,彻底解决重复问题 + // 响铃状态 case CALL_STATE_RINGING: LogUtils.d(TAG, "onStateChanged: 通话处于响铃状态"); break; + // 空闲状态(通话挂断后) case CALL_STATE_IDLE: - LogUtils.d(TAG, "onStateChanged: 通话挂断,停止录音"); - stopRecording(); + LogUtils.d(TAG, "onStateChanged: 通话挂断"); break; + // 通话断开,关闭界面 case CALL_STATE_DISCONNECTED: ActivityStack.getInstance().finishActivity(PhoneCallActivity.class); LogUtils.d(TAG, "onStateChanged: 通话断开,关闭通话界面"); break; + // 通话连接中 case CALL_STATE_CONNECTING: LogUtils.d(TAG, "onStateChanged: 通话正在连接"); break; @@ -149,7 +126,7 @@ public class PhoneCallService extends InCallService { }; } - // ====================== 核心业务方法区 ====================== + // ====================== 核心业务方法区(铃音控制+黑白名单) ====================== private CallType judgeCallType(int callState) { switch (callState) { case CALL_STATE_RINGING: @@ -232,90 +209,7 @@ public class PhoneCallService extends InCallService { LogUtils.d(TAG, "startPhoneCallActivity: 通话界面已启动"); } - // ====================== 录音相关方法区 ====================== - private void startRecording(long callId) { - releaseRecorder(); - mMediaRecorder = new MediaRecorder(); - try { - mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.VOICE_CALL); - mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); - mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); - String path = getOutputFilePath(callId); - mMediaRecorder.setOutputFile(path); - mMediaRecorder.prepare(); - mMediaRecorder.start(); - LogUtils.d(TAG, "startRecording: 录音启动成功 | 路径=" + path); - } catch (IOException | IllegalStateException e) { - LogUtils.e(TAG, "startRecording: 录音启动失败", e); - releaseRecorder(); - } - } - - private void stopRecording() { - if (mMediaRecorder != null) { - try { - mMediaRecorder.stop(); - } catch (IllegalStateException e) { - LogUtils.e(TAG, "stopRecording: 录音停止失败", e); - } finally { - releaseRecorder(); - } - } - } - - private String getOutputFilePath(long callId) { - File dir = getExternalFilesDir(TAG); - if (dir == null) { - dir = new File(getFilesDir(), TAG); - if (!dir.exists()) { - dir.mkdirs(); - } - } - return new File(dir, String.format("call_%d.mp4", callId)).getAbsolutePath(); - } - - private void releaseRecorder() { - if (mMediaRecorder != null) { - mMediaRecorder.release(); - mMediaRecorder = null; - LogUtils.d(TAG, "releaseRecorder: 录音资源已释放"); - } - } - // ====================== 辅助工具方法区 ====================== - private long getCurrentCallId() { - ContentResolver resolver = getApplicationContext().getContentResolver(); - if (resolver == null) { - LogUtils.w(TAG, "getCurrentCallId: 内容解析器为null"); - return -1; - } - - Uri uri = CallLog.Calls.CONTENT_URI; - String[] projection = {CallLog.Calls._ID}; - String selection = CallLog.Calls.TYPE + " = " + CallLog.Calls.OUTGOING_TYPE - + " OR " + CallLog.Calls.TYPE + " = " + CallLog.Calls.INCOMING_TYPE; - String sort = CallLog.Calls.DATE + " DESC"; - Cursor cursor = null; - - try { - cursor = resolver.query(uri, projection, selection, null, sort); - if (cursor != null && cursor.moveToFirst()) { - long id = cursor.getLong(cursor.getColumnIndex(CallLog.Calls._ID)); - LogUtils.d(TAG, "getCurrentCallId: 通话ID=" + id); - return id; - } - LogUtils.w(TAG, "getCurrentCallId: 未查询到通话记录"); - return -1; - } catch (SecurityException e) { - LogUtils.e(TAG, "getCurrentCallId: 查询失败(权限不足)", e); - return -1; - } finally { - if (cursor != null) { - cursor.close(); - } - } - } - private String getCallStateDesc(int state) { switch (state) { case CALL_STATE_RINGING: @@ -324,8 +218,6 @@ public class PhoneCallService extends InCallService { return "连接中"; case CALL_STATE_ACTIVE: return "活跃"; - //case CALL_STATE_OFFHOOK: - // return "摘机"; case CALL_STATE_IDLE: return "空闲"; case CALL_STATE_DISCONNECTED: @@ -334,5 +226,18 @@ public class PhoneCallService extends InCallService { return "未知状态"; } } + + // ====================== 静态内部类:PhoneCallManager(避免编译报错) ====================== + public static class PhoneCallManager { + public static Call sCurrentCall; + + private PhoneCallManager() { + // 私有构造,禁止实例化 + } + + public static Call getCurrentCall() { + return sCurrentCall; + } + } } diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/services/AssistantService.java b/contacts/src/main/java/cc/winboll/studio/contacts/services/AssistantService.java index 014ed45..001a427 100644 --- a/contacts/src/main/java/cc/winboll/studio/contacts/services/AssistantService.java +++ b/contacts/src/main/java/cc/winboll/studio/contacts/services/AssistantService.java @@ -10,13 +10,9 @@ import android.content.Intent; import android.content.ServiceConnection; import android.os.Binder; import android.os.Build; -import android.os.Handler; import android.os.IBinder; -import android.os.Looper; - import cc.winboll.studio.contacts.R; import cc.winboll.studio.contacts.model.MainServiceBean; -import cc.winboll.studio.contacts.utils.AppForegroundUtils; import cc.winboll.studio.libappbase.LogUtils; /** @@ -159,7 +155,7 @@ public class AssistantService extends Service { LogUtils.d(TAG, "onCreate: 守护服务创建"); // 适配 Android 12+ 后台启动限制:应用后台时启动为前台服务 - if (Build.VERSION.SDK_INT >= ANDROID_12_API && !AppForegroundUtils.isAppForeground(this)) { + if (Build.VERSION.SDK_INT >= ANDROID_12_API) { Notification notification = createForegroundNotification(); // 修复:使用 dataSync 类型,添加异常捕获防止崩溃 try { @@ -256,7 +252,7 @@ public class AssistantService extends Service { Intent intent = new Intent(this, MainService.class); // 根据应用前后台状态选择启动方式(Android 12+ 后台用 startForegroundService) - if (Build.VERSION.SDK_INT >= ANDROID_12_API && !AppForegroundUtils.isAppForeground(this)) { + if (Build.VERSION.SDK_INT >= ANDROID_12_API) { LogUtils.d(TAG, "wakeupAndBindMain: 应用后台,启动主服务为前台服务"); startForegroundService(intent); } else { 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 3b49f11..c465cff 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 @@ -23,8 +23,6 @@ import cc.winboll.studio.contacts.listenphonecall.CallListenerService; import cc.winboll.studio.contacts.model.MainServiceBean; import cc.winboll.studio.contacts.model.RingTongBean; import cc.winboll.studio.contacts.receivers.MainReceiver; -import cc.winboll.studio.contacts.threads.MainServiceThread; -import cc.winboll.studio.contacts.utils.AppForegroundUtils; import cc.winboll.studio.libappbase.LogUtils; import java.util.Timer; import java.util.TimerTask; @@ -34,7 +32,7 @@ import java.util.TimerTask; * @Date 2025/02/13 06:56:41 * @Describe 拨号主服务,负责核心业务逻辑、守护进程绑定、铃声音量监控及通话监听启动 * 严格适配 Android API 30 + Java 7 语法规范 | 解决前台服务启动超时崩溃 - * 新增:统一在 mainService() 中启动电话监听服务 + 通话筛选服务 + * 优化:移除延迟启动,非核心服务直接在 mainService() 中启动 */ public class MainService extends Service { // ====================== 常量定义区(全硬编码,杜绝高版本 API 依赖) ====================== @@ -52,9 +50,8 @@ public class MainService extends Service { private static final int ANDROID_8_API = 26; private static final int ANDROID_10_API = 29; private static final int ANDROID_12_API = 31; - // 重试延迟时间 & 非核心服务延迟启动时间 + // 重试延迟时间(仅保留守护服务重绑定延迟,移除非核心服务延迟) private static final long RETRY_DELAY_MS = 3000L; - private static final long DELAY_NON_CORE_SERVICE_MS = 100L; // ====================== 静态成员变量区 ====================== private static MainService sMainServiceInstance; @@ -63,14 +60,13 @@ public class MainService extends Service { // ====================== 成员变量区 ====================== private volatile boolean mIsServiceRunning; private MainServiceBean mMainServiceBean; - private MainServiceThread mMainServiceThread; + //private MainServiceThread mMainServiceThread; private MainServiceHandler mMainServiceHandler; private MyServiceConnection mMyServiceConnection; private AssistantService mAssistantService; private boolean mIsBound; private MainReceiver mMainReceiver; private Timer mStreamVolumeCheckTimer; - private Handler mDelayHandler; // ====================== Binder 内部类 ====================== public class MyBinder extends Binder { @@ -147,13 +143,7 @@ public class MainService extends Service { } LogUtils.d(TAG, "startMainService: 执行启动主服务操作"); Intent intent = new Intent(context, MainService.class); - // API 30 属于 Android 10+,按前台服务逻辑处理 - if (Build.VERSION.SDK_INT >= ANDROID_10_API && !AppForegroundUtils.isAppForeground(context)) { - LogUtils.d(TAG, "startMainService: 应用后台,使用 startForegroundService 启动"); - context.startForegroundService(intent); - } else { - context.startService(intent); - } + context.startForegroundService(intent); } public static void restartMainService(Context context) { @@ -194,6 +184,7 @@ public class MainService extends Service { MainServiceBean bean = new MainServiceBean(); bean.setIsEnable(true); MainServiceBean.saveBean(context, bean); + stopMainService(context); startMainService(context); } @@ -213,52 +204,6 @@ public class MainService extends Service { } } - /** - * 服务启动前置校验 - */ - private boolean canStartService(Class serviceClass) { - // 服务未启用/已运行 → 禁止启动 - if (mMainServiceBean == null || !mMainServiceBean.isEnable()) { - LogUtils.w(TAG, "canStartService: 主服务未启用,禁止启动 " + serviceClass.getSimpleName()); - return false; - } - if (isServiceRunning(serviceClass)) { - LogUtils.d(TAG, "canStartService: " + serviceClass.getSimpleName() + " 已运行,跳过启动"); - return false; - } - // Android 12+ 应用后台 → 禁止启动非核心服务 - if (Build.VERSION.SDK_INT >= ANDROID_12_API && !AppForegroundUtils.isAppForeground(this)) { - LogUtils.w(TAG, "canStartService: Android 12+ 应用后台,禁止启动 " + serviceClass.getSimpleName()); - return false; - } - return true; - } - - /** - * 延迟启动非核心服务 - */ - private void delayStartNonCoreService(final Class serviceClass) { - if (!canStartService(serviceClass)) { - return; - } - mDelayHandler.postDelayed(new Runnable() { - @Override - public void run() { - Intent intent = new Intent(MainService.this, serviceClass); - try { - if (Build.VERSION.SDK_INT >= ANDROID_10_API && !AppForegroundUtils.isAppForeground(MainService.this)) { - startForegroundService(intent); - } else { - startService(intent); - } - LogUtils.d(TAG, "delayStartNonCoreService: " + serviceClass.getSimpleName() + " 启动成功"); - } catch (Exception e) { - LogUtils.e(TAG, "delayStartNonCoreService: " + serviceClass.getSimpleName() + " 启动失败", e); - } - } - }, DELAY_NON_CORE_SERVICE_MS); - } - /** * 创建前台服务通知 */ @@ -299,25 +244,6 @@ public class MainService extends Service { return builder.build(); } - /** - * 启动电话监听服务(原有:CallListenerService) - */ - private void startPhoneCallListener() { - delayStartNonCoreService(CallListenerService.class); - } - - /** - * 新增:启动通话筛选服务(MyCallScreeningService,API 10+ 生效) - */ - private void startCallScreeningService() { - // 通话筛选服务仅 Android 10+(API 29+)支持,低版本跳过 - if (Build.VERSION.SDK_INT >= ANDROID_10_API) { - delayStartNonCoreService(MyCallScreeningService.class); - } else { - LogUtils.d(TAG, "startCallScreeningService: 系统版本低于 Android 10,不支持通话筛选服务,跳过启动"); - } - } - /** * 检查服务是否正在运行 */ @@ -349,15 +275,17 @@ public class MainService extends Service { sMainServiceInstance = this; mIsServiceRunning = false; - // 仅初始化核心组件 + // 仅初始化核心组件(移除 mDelayHandler 初始化,无需延迟启动) mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class); mMyServiceConnection = new MyServiceConnection(); mMainServiceHandler = new MainServiceHandler(this); - mDelayHandler = new Handler(Looper.getMainLooper()); // 初始化铃声音量检查定时器 initVolumeCheckTimer(); + // 启动服务 + mainService(); + LogUtils.d(TAG, "===== onCreate: 主服务创建完成(仅初始化组件) ====="); } @@ -380,19 +308,10 @@ public class MainService extends Service { super.onDestroy(); LogUtils.d(TAG, "===== onDestroy: 主服务开始销毁(强制清理所有资源) ====="); - // 1. 强制标记服务为未运行 - mIsServiceRunning = false; - - // 2. 释放延迟 Handler 资源 - if (mDelayHandler != null) { - mDelayHandler.removeCallbacksAndMessages(null); - mDelayHandler = null; - } - - // 3. 释放定时器资源 + // 2. 释放定时器资源 cancelVolumeCheckTimer(); - // 4. 强制解除守护服务绑定 + // 3. 强制解除守护服务绑定 if (mIsBound && mMyServiceConnection != null) { try { unbindService(mMyServiceConnection); @@ -404,97 +323,101 @@ public class MainService extends Service { mMyServiceConnection = null; } - // 5. 强制注销广播接收器 + // 4. 强制注销广播接收器 if (mMainReceiver != null) { mMainReceiver.unregisterAction(this); mMainReceiver = null; LogUtils.d(TAG, "onDestroy: 广播接收器已注销"); } - // 6. 强制停止主业务线程 - if (mMainServiceThread != null) { - mMainServiceThread.setIsExit(true); - mMainServiceThread = null; - } + // 5. 强制停止主业务线程 +// if (mMainServiceThread != null) { +// mMainServiceThread.setIsExit(true); +// mMainServiceThread = null; +// } - // 7. 强制停止所有子服务(新增:停止通话筛选服务 MyCallScreeningService) + // 6. 强制停止所有子服务 stopService(new Intent(this, AssistantService.class)); stopService(new Intent(this, CallListenerService.class)); stopService(new Intent(this, MyCallScreeningService.class)); LogUtils.d(TAG, "onDestroy: 所有子服务已强制停止"); - // 8. 清空静态实例,避免内存泄漏(不改动 Bean 配置) + // 7. 清空静态实例,避免内存泄漏(不改动 Bean 配置) sMainServiceInstance = null; sTomCatInstance = null; mMainServiceHandler = null; mAssistantService = null; mMainServiceBean = null; + // 标记服务为未运行 + mIsServiceRunning = false; LogUtils.d(TAG, "===== onDestroy: 主服务销毁完成(资源全清理,Bean 配置无改动) ====="); } - // ====================== 核心业务逻辑:优先判断运行状态 → 再校验配置启用状态 ====================== - private void mainService() { + // ====================== 核心业务逻辑:非核心服务直接启动,无延迟 ====================== + private synchronized void mainService() { LogUtils.d(TAG, "mainService: 执行核心业务逻辑"); // 第一步:优先判断服务是否已运行,已运行则直接退出(不做任何动作) - if (mIsServiceRunning) { - LogUtils.d(TAG, "mainService: 服务已处于运行状态,直接退出"); - return; - } + if (!mIsServiceRunning) { + mIsServiceRunning = true; + // 第二步:加载最新配置,校验服务是否启用(未启用则退出) + mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class); + if (mMainServiceBean == null && mMainServiceBean.isEnable()) { + // 第三步:配置启用且服务未运行,执行启动流程 + LogUtils.i(TAG, "mainService: 服务未运行且配置已启用,开始启动核心流程"); - // 第二步:加载最新配置,校验服务是否启用(未启用则退出) - mMainServiceBean = MainServiceBean.loadBean(this, MainServiceBean.class); - if (mMainServiceBean == null || !mMainServiceBean.isEnable()) { - LogUtils.w(TAG, "mainService: 服务配置未启用/配置加载失败,退出启动流程"); - return; - } + // 1. 启动前台服务(优先执行,避免超时) + try { + Notification foregroundNotification = createForegroundNotification(); + startForeground(FOREGROUND_NOTIFICATION_ID, foregroundNotification, FOREGROUND_SERVICE_TYPE_DATA_SYNC); + //startForeground(FOREGROUND_NOTIFICATION_ID, foregroundNotification); + } catch (IllegalArgumentException e) { + LogUtils.e(TAG, "mainService: 启动前台服务失败,类型不匹配", e); + mIsServiceRunning = false; + stopSelf(); + return; + } catch (Exception e) { + LogUtils.e(TAG, "mainService: 启动前台服务异常", e); + mIsServiceRunning = false; + stopSelf(); + return; + } - // 第三步:配置启用且服务未运行,执行启动流程 - mIsServiceRunning = true; - LogUtils.i(TAG, "mainService: 服务未运行且配置已启用,开始启动核心流程"); + // 2. 绑定守护服务 + wakeupAndBindAssistant(); - // 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; - } + // 3. 初始化业务组件 + initTomCat(); + initMainReceiver(); + Rules.getInstance(this).loadRules(); + LogUtils.d(TAG, "mainService: 黑白名单规则已加载"); - // 2. 绑定守护服务 - wakeupAndBindAssistant(); + // 4. 直接启动电话监听服务(移除延迟,校验通过则立即启动) + Intent callListenerIntent = new Intent(this, CallListenerService.class); + try { + startForegroundService(callListenerIntent); + //startService(callListenerIntent); + } catch (Exception e) { + LogUtils.e(TAG, "mainService: CallListenerService 启动失败", e); + } - // 3. 初始化业务组件 - initTomCat(); - initMainReceiver(); - Rules.getInstance(this).loadRules(); - LogUtils.d(TAG, "mainService: 黑白名单规则已加载"); - // 4. 启动电话监听服务(原有:CallListenerService) - startPhoneCallListener(); + // 5. 直接启动通话筛选服务(API 10+ 生效,无延迟) + Intent screeningIntent = new Intent(this, MyCallScreeningService.class); + try { + startForegroundService(screeningIntent); + //startService(screeningIntent); + } catch (Exception e) { + LogUtils.e(TAG, "mainService: MyCallScreeningService 启动失败", e); + } - // 5. 新增:启动通话筛选服务(MyCallScreeningService,API 10+ 生效) - startCallScreeningService(); - - // 6. 启动主业务线程 - mMainServiceThread = MainServiceThread.getInstance(this, mMainServiceHandler); - mMainServiceThread.start(); - LogUtils.i(TAG, "mainService: 核心流程启动完成,主服务正常运行"); + // 6. 启动主业务线程 +// mMainServiceThread = MainServiceThread.getInstance(this, mMainServiceHandler); +// mMainServiceThread.start(); + LogUtils.i(TAG, "mainService: 核心流程启动完成,主服务正常运行"); + } + } } private void wakeupAndBindAssistant() { @@ -503,7 +426,7 @@ public class MainService extends Service { return; } Intent intent = new Intent(this, AssistantService.class); - if (Build.VERSION.SDK_INT >= ANDROID_10_API && !AppForegroundUtils.isAppForeground(this)) { + if (Build.VERSION.SDK_INT >= ANDROID_10_API) { LogUtils.d(TAG, "wakeupAndBindAssistant: 应用后台,启动 AssistantService 为前台服务"); startForegroundService(intent); } else { diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/utils/AppForegroundUtils.java b/contacts/src/main/java/cc/winboll/studio/contacts/utils/AppForegroundUtils.java deleted file mode 100644 index 3f7a78b..0000000 --- a/contacts/src/main/java/cc/winboll/studio/contacts/utils/AppForegroundUtils.java +++ /dev/null @@ -1,52 +0,0 @@ -package cc.winboll.studio.contacts.utils; - -import android.app.ActivityManager; -import android.content.Context; -import android.os.Build; -import android.text.TextUtils; - -import java.util.List; - -/** - * @Author ZhanGSKen&豆包大模型 - * @Date 2025/12/12 15:20 - * @Describe AppForegroundUtils 应用前后台状态判断工具类(兼容 Java 7) - */ -public class AppForegroundUtils { - - public static final String TAG = "AppForegroundUtils"; - - /** - * 判断应用是否处于前台状态 - * @param context 上下文 - * @return true-前台,false-后台/无上下文 - */ - public static boolean isAppForeground(Context context) { - if (context == null) { - return false; - } - - ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); - if (activityManager == null) { - return false; - } - - String packageName = context.getPackageName(); - List processList = activityManager.getRunningAppProcesses(); - if (processList == null || processList.isEmpty()) { - return false; - } - - // 遍历进程列表,匹配当前应用包名并判断前台状态 - for (ActivityManager.RunningAppProcessInfo processInfo : processList) { - // Java 7 兼容:避免 Lambda,使用普通循环 + TextUtils 判等 - if (!TextUtils.isEmpty(processInfo.processName) - && TextUtils.equals(processInfo.processName, packageName) - && processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) { - return true; - } - } - return false; - } -} -