|
@@ -15,6 +15,7 @@ import android.os.Looper
|
|
|
import android.os.Message
|
|
import android.os.Message
|
|
|
import android.os.Messenger
|
|
import android.os.Messenger
|
|
|
import android.os.ParcelFileDescriptor
|
|
import android.os.ParcelFileDescriptor
|
|
|
|
|
+import android.os.SystemClock
|
|
|
import androidx.core.app.NotificationCompat
|
|
import androidx.core.app.NotificationCompat
|
|
|
import app.xixi.nomo.XRayApi.Companion.VPN_STATE_CONNECTED
|
|
import app.xixi.nomo.XRayApi.Companion.VPN_STATE_CONNECTED
|
|
|
import app.xixi.nomo.XRayApi.Companion.VPN_STATE_ERROR
|
|
import app.xixi.nomo.XRayApi.Companion.VPN_STATE_ERROR
|
|
@@ -33,37 +34,41 @@ class XRayService : VpnService() {
|
|
|
private val timerHandler = Handler(Looper.getMainLooper())
|
|
private val timerHandler = Handler(Looper.getMainLooper())
|
|
|
private var isTimerRunning = false
|
|
private var isTimerRunning = false
|
|
|
private var isTimerPaused = false
|
|
private var isTimerPaused = false
|
|
|
- private var currentTimerTime = 0L
|
|
|
|
|
- private var timerStartTime = 0L
|
|
|
|
|
private var timerMode = 0 // 0: 普通计时, 1: 倒计时
|
|
private var timerMode = 0 // 0: 普通计时, 1: 倒计时
|
|
|
|
|
|
|
|
|
|
+ // 使用 SystemClock.elapsedRealtime() 确保时间准确性(包括休眠时间)
|
|
|
|
|
+ private var timerBaseRealtime = 0L // 计时开始的真实时间(elapsedRealtime)
|
|
|
|
|
+ private var timerInitialTime = 0L // 初始时间(对于倒计时是总时长,对于正常计时是0或已用时间)
|
|
|
|
|
+ private var timerPausedElapsed = 0L // 暂停时已经过的时间
|
|
|
|
|
+
|
|
|
// 计时器Runnable
|
|
// 计时器Runnable
|
|
|
private val timerRunnable = object : Runnable {
|
|
private val timerRunnable = object : Runnable {
|
|
|
override fun run() {
|
|
override fun run() {
|
|
|
if (isTimerRunning && !isTimerPaused) {
|
|
if (isTimerRunning && !isTimerPaused) {
|
|
|
- val newTime = if (timerMode == 0) {
|
|
|
|
|
- // 普通计时:递增
|
|
|
|
|
- currentTimerTime + 1000L
|
|
|
|
|
|
|
+ // 计算从开始到现在经过的真实时间
|
|
|
|
|
+ val elapsedTime = SystemClock.elapsedRealtime() - timerBaseRealtime
|
|
|
|
|
+
|
|
|
|
|
+ val currentTime = if (timerMode == 0) {
|
|
|
|
|
+ // 普通计时:初始时间 + 经过时间
|
|
|
|
|
+ timerInitialTime + elapsedTime
|
|
|
} else {
|
|
} else {
|
|
|
- // 倒计时:递减
|
|
|
|
|
- currentTimerTime - 1000L
|
|
|
|
|
|
|
+ // 倒计时:初始时间 - 经过时间
|
|
|
|
|
+ timerInitialTime - elapsedTime
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- currentTimerTime = newTime
|
|
|
|
|
-
|
|
|
|
|
// 检查倒计时是否结束
|
|
// 检查倒计时是否结束
|
|
|
- if (timerMode == 1 && newTime <= 0) {
|
|
|
|
|
- VLog.i(TAG, "倒计时结束 - 关闭VPN")
|
|
|
|
|
|
|
+ if (timerMode == 1 && currentTime <= 0) {
|
|
|
|
|
+ VLog.i(TAG, "倒计时结束 - 关闭VPN (elapsed: ${elapsedTime}ms)")
|
|
|
dealStopMsg()
|
|
dealStopMsg()
|
|
|
notifyStop()
|
|
notifyStop()
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 更新通知
|
|
// 更新通知
|
|
|
- updateNotification()
|
|
|
|
|
|
|
+ updateNotification(currentTime)
|
|
|
|
|
|
|
|
// 发送计时更新
|
|
// 发送计时更新
|
|
|
- sendTimerUpdate()
|
|
|
|
|
|
|
+ sendTimerUpdate(currentTime)
|
|
|
|
|
|
|
|
// 继续下一秒
|
|
// 继续下一秒
|
|
|
timerHandler.postDelayed(this, 1000L)
|
|
timerHandler.postDelayed(this, 1000L)
|
|
@@ -311,8 +316,9 @@ class XRayService : VpnService() {
|
|
|
return
|
|
return
|
|
|
VLog.i(TAG, "启动计时: mode=$mode, initialTime=$initialTime")
|
|
VLog.i(TAG, "启动计时: mode=$mode, initialTime=$initialTime")
|
|
|
timerMode = mode
|
|
timerMode = mode
|
|
|
- currentTimerTime = initialTime
|
|
|
|
|
- timerStartTime = System.currentTimeMillis()
|
|
|
|
|
|
|
+ timerInitialTime = initialTime
|
|
|
|
|
+ timerBaseRealtime = SystemClock.elapsedRealtime()
|
|
|
|
|
+ timerPausedElapsed = 0L
|
|
|
|
|
|
|
|
isTimerRunning = true
|
|
isTimerRunning = true
|
|
|
isTimerPaused = false
|
|
isTimerPaused = false
|
|
@@ -331,8 +337,12 @@ class XRayService : VpnService() {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private fun pauseTimer() {
|
|
private fun pauseTimer() {
|
|
|
- if (isTimerRunning) {
|
|
|
|
|
- VLog.i(TAG, "暂停计时")
|
|
|
|
|
|
|
+ if (isTimerRunning && !isTimerPaused) {
|
|
|
|
|
+ // 记录暂停时已经过的时间
|
|
|
|
|
+ val elapsedTime = SystemClock.elapsedRealtime() - timerBaseRealtime
|
|
|
|
|
+ timerPausedElapsed = elapsedTime
|
|
|
|
|
+
|
|
|
|
|
+ VLog.i(TAG, "暂停计时 (已用: ${elapsedTime}ms)")
|
|
|
isTimerPaused = true
|
|
isTimerPaused = true
|
|
|
timerHandler.removeCallbacks(timerRunnable)
|
|
timerHandler.removeCallbacks(timerRunnable)
|
|
|
}
|
|
}
|
|
@@ -340,27 +350,31 @@ class XRayService : VpnService() {
|
|
|
|
|
|
|
|
private fun resumeTimer() {
|
|
private fun resumeTimer() {
|
|
|
if (isTimerRunning && isTimerPaused) {
|
|
if (isTimerRunning && isTimerPaused) {
|
|
|
- VLog.i(TAG, "恢复计时")
|
|
|
|
|
|
|
+ VLog.i(TAG, "恢复计时 (之前已用: ${timerPausedElapsed}ms)")
|
|
|
|
|
+
|
|
|
|
|
+ // 恢复时重新设置基准时间,但要减去之前已经过的时间
|
|
|
|
|
+ timerBaseRealtime = SystemClock.elapsedRealtime() - timerPausedElapsed
|
|
|
|
|
+
|
|
|
isTimerPaused = false
|
|
isTimerPaused = false
|
|
|
timerHandler.post(timerRunnable)
|
|
timerHandler.post(timerRunnable)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- private fun sendTimerUpdate() {
|
|
|
|
|
|
|
+ private fun sendTimerUpdate(currentTime: Long) {
|
|
|
try {
|
|
try {
|
|
|
replyMessenger?.let { messenger ->
|
|
replyMessenger?.let { messenger ->
|
|
|
try {
|
|
try {
|
|
|
val msg = Message.obtain().apply {
|
|
val msg = Message.obtain().apply {
|
|
|
what = XRAY_MSG_REPLY_TIMER_UPDATE
|
|
what = XRAY_MSG_REPLY_TIMER_UPDATE
|
|
|
data = Bundle().apply {
|
|
data = Bundle().apply {
|
|
|
- putLong("currentTime", currentTimerTime)
|
|
|
|
|
|
|
+ putLong("currentTime", currentTime)
|
|
|
putInt("mode", timerMode)
|
|
putInt("mode", timerMode)
|
|
|
putBoolean("isRunning", isTimerRunning)
|
|
putBoolean("isRunning", isTimerRunning)
|
|
|
putBoolean("isPaused", isTimerPaused)
|
|
putBoolean("isPaused", isTimerPaused)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
messenger.send(msg)
|
|
messenger.send(msg)
|
|
|
- VLog.i(TAG, "计时更新消息已发送: time=$currentTimerTime, mode=$timerMode")
|
|
|
|
|
|
|
+ VLog.i(TAG, "计时更新消息已发送: time=$currentTime, mode=$timerMode")
|
|
|
} catch (e: DeadObjectException) {
|
|
} catch (e: DeadObjectException) {
|
|
|
VLog.w(TAG, "Messenger已失效,清理引用", e)
|
|
VLog.w(TAG, "Messenger已失效,清理引用", e)
|
|
|
replyMessenger = null
|
|
replyMessenger = null
|
|
@@ -375,8 +389,8 @@ class XRayService : VpnService() {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- private fun updateNotification() {
|
|
|
|
|
- val timeText = formatTime(currentTimerTime)
|
|
|
|
|
|
|
+ private fun updateNotification(currentTime: Long) {
|
|
|
|
|
+ val timeText = formatTime(currentTime)
|
|
|
val modeText = if (timerMode == 0) "计时中" else "倒计时"
|
|
val modeText = if (timerMode == 0) "计时中" else "倒计时"
|
|
|
val statusText = if (isTimerPaused) "已暂停" else "运行中"
|
|
val statusText = if (isTimerPaused) "已暂停" else "运行中"
|
|
|
|
|
|