diff --git a/app/src/main/java/com/nbee/echolink/service/MonitorService.java b/app/src/main/java/com/nbee/echolink/service/MonitorService.java index 1482f60..3e02c11 100644 --- a/app/src/main/java/com/nbee/echolink/service/MonitorService.java +++ b/app/src/main/java/com/nbee/echolink/service/MonitorService.java @@ -50,8 +50,8 @@ public class MonitorService extends Service { /** * 服务启动时的命令处理。 * - * @param intent 携带启动服务的意图,可能包含来电或短信的信息。 - * @param flags 启动标志,提供额外数据。 + * @param intent 携带启动服务的意图,可能包含来电或短信的信息。 + * @param flags 启动标志,提供额外数据。 * @param startId 一个唯一的整数,标识此启动请求。 * @return 返回START_STICKY,如果系统在服务终止后杀死,则重新创建服务并调用onStartCommand(),但不重新传递最后的意图。 */ @@ -73,6 +73,17 @@ public class MonitorService extends Service { } + /** + * 将来电信息发送到服务器。 + * + * @param incomingNumber 接收到的电话号码。 + * 该方法首先检查传入的电话号码是否为"null"或null, + * 如果是,则不执行任何操作。 + * 其次,如果电话号码与上一个来电号码相同,并且时间间隔小于70秒, + * 也不会执行发送操作,以避免频繁发送相同信息。 + * 如果通过所有检查,将创建一个包含来电信息的CallInfo对象, + * 并使用网络工具将其发送到服务器。 + */ private void sendCallInfoToServer(String incomingNumber) { Timber.d("sendCallInfoToServer: 处理来电信息"); if (incomingNumber.equals("null") || incomingNumber == null) { @@ -91,59 +102,101 @@ public class MonitorService extends Service { lastCallTime = currentTimeMillis; String currentTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()); + // 创建CallInfo对象并设置相关信息,然后发送到服务器 CallInfo callInfo = new CallInfo(); callInfo.setCallTime(currentTime); callInfo.setPhoneNumber(incomingNumber); networkUtils.postRequest(callInfo); } + + /** + * 向服务器发送短信信息。 + * + * @param sender 发送者的手机号码。 + * @param messageBody 短信的内容。 + * 该方法首先会检查发送者和短信内容是否为空,如果为空则不进行任何操作。 + * 接着,它会格式化当前时间,并创建一个SMSInfo对象,将发送者、短信内容和接收时间设置到这个对象中。 + * 最后,使用网络工具将这个SMSInfo对象以POST请求的方式发送到服务器。 + */ private void sendSmsInfoToServer(String sender, String messageBody) { Timber.d("sendSmsInfoToServer: 处理短信信息"); if (checkNullString(sender, messageBody)) { return; } + // 获取当前时间并格式化 String currentTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()); + // 创建SMSInfo对象并设置相关属性 SMSInfo smsInfo = new SMSInfo(); smsInfo.setSmsNumber(sender); smsInfo.setSmsContent(messageBody); smsInfo.setSmsAcceptanceTime(currentTime); + // 使用网络工具发送POST请求 networkUtils.postRequest(smsInfo); } + /** + * 发送微信消息。 + * 使用网络工具类向指定地址发送微信消息。 + * + * @param weChatMsg 微信消息对象,包含消息的全部必要信息。 + */ public void sendWeChatMsg(WeChatMsg weChatMsg) { networkUtils.postRequest(weChatMsg); + // 使用网络工具类发送POST请求,将微信消息发送出去。 } + /** + * 检查两个字符串是否为null或"null"。 + * + * @param a 第一个字符串 + * @param b 第二个字符串 + * @return 如果任一字符串为null或者"null",返回true;否则返回false。 + */ private boolean checkNullString(String a, String b) { + // 检查任一字符串是否为null if (a == null || b == null) { return true; } + // 检查任一字符串是否等于"null" if (a.equals("null") || b.equals("null")) { return true; } return false; } + /** + * 启动一个前台服务。该方法首先会检查系统版本,如果是在API 26及以上版本,就会创建一个通知频道。 + * 然后,构建一个通知对象,并使用该通知启动前台服务。前台服务能够在后台持续运行,即使应用被关闭或压入后台, + * 也能保持服务的运行状态,常用于需要持续运行的服务。 + */ private void startForegroundService() { Timber.d("startForegroundService: 启动前台服务"); - // 创建通知频道(仅在API 26及以上版本中需要) + // 检测系统版本,仅在API 26及以上版本创建通知频道 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel("channel_id", "Channel Name", NotificationManager.IMPORTANCE_DEFAULT); NotificationManager notificationManager = getSystemService(NotificationManager.class); notificationManager.createNotificationChannel(channel); } - // 创建通知 + // 创建通知对象。通知内容包括标题、小图标等 Notification notification = new NotificationCompat.Builder(this, "channel_id") .setContentTitle(getString(R.string.notification_title)) //.setContentText("sdads") - .setSmallIcon(R.drawable.ic_notification) // 确保您有这个图标 + .setSmallIcon(R.drawable.ic_notification) // 设置通知的小图标 .build(); - // 启动前台服务 + // 使用创建的通知启动前台服务 startForeground(1, notification); } + + /** + * 当其他组件请求与服务绑定时调用此方法。该服务不提供绑定接口,因此总是返回null。 + * + * @param intent 指示服务应该执行的操作的Intent。包含请求绑定的服务的信息。 + * @return 返回null,表示该服务不支持绑定操作。 + */ @Nullable @Override public IBinder onBind(Intent intent) { @@ -151,18 +204,33 @@ public class MonitorService extends Service { return null; // 不提供绑定服务的接口 } + + /** + * 调度心跳监测。此函数用于设置一个定时任务,以便周期性地触发心跳事件。 + * 心跳事件通过广播的形式由系统自动触发,用于维持应用程序在后台的活性或执行定期任务。 + * + * @param context 应用程序的上下文环境,用于访问系统的各种服务。 + */ public static void scheduleHeartbeat(Context context) { + // 获取系统的闹钟服务 AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); + // 创建一个意图,指定当闹钟触发时要执行的广播接收器 Intent intent = new Intent(context, HeartbeatAlarmReceiver.class); + // 根据意图和标志位创建一个唯一的PendingIntent,系统通过这个PendingIntent触发广播 PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0); + // 计算心跳事件的触发间隔,单位为毫秒 long intervalMillis = HEARTBEAT_INTERVAL_MINUTES * 60 * 1000; // 10分钟的毫秒数 + // 根据Android版本选择合适的闹钟设置方法,以确保闹钟在设备休眠时也能触发 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + // 对于6.0及以上版本,使用setExactAndAllowWhileIdle方法,可以在设备闲置时精确安排闹钟 alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + intervalMillis, pendingIntent); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + // 对于4.4到6.0版本,使用setExact方法,可以精确安排闹钟 alarmManager.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + intervalMillis, pendingIntent); } else { + // 对于更早的版本,使用set方法,可以安排一个带宽醒目的闹钟 alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + intervalMillis, pendingIntent); } }