fix time error

This commit is contained in:
Li ZongYing
2024-02-07 19:21:17 +08:00
parent aa4d52681f
commit 764f2a1549
11 changed files with 278 additions and 26 deletions
+5
View File
@@ -14,6 +14,11 @@
## 更新日志 ## 更新日志
### v1.5.6(通用版)
* 解决部分设备系统时间不对导致播放失败的问题
*
### v1.5.2(通用版) ### v1.5.2(通用版)
* 修复APP恢复后频道号、频道列表不自动消失的问题 * 修复APP恢复后频道号、频道列表不自动消失的问题
@@ -18,16 +18,22 @@ import android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
import android.view.WindowManager import android.view.WindowManager
import android.widget.Toast import android.widget.Toast
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.lifecycleScope
import com.lizongying.mytv.models.TVViewModel import com.lizongying.mytv.models.TVViewModel
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import java.security.MessageDigest import java.security.MessageDigest
class MainActivity : FragmentActivity() { class MainActivity : FragmentActivity() {
var playerFragment = PlayerFragment() private var ready = 0
private val mainFragment = MainFragment() private var playerFragment = PlayerFragment()
private val infoFragment = InfoFragment() private var mainFragment = MainFragment()
private val channelFragment = ChannelFragment() private var infoFragment = InfoFragment()
private var channelFragment = ChannelFragment()
private lateinit var settingFragment: SettingFragment private lateinit var settingFragment: SettingFragment
private var doubleBackToExitPressedOnce = false private var doubleBackToExitPressedOnce = false
@@ -44,6 +50,16 @@ class MainActivity : FragmentActivity() {
private var versionName = "" private var versionName = ""
init {
lifecycleScope.launch(Dispatchers.IO) {
val utilsJob = async(start = CoroutineStart.LAZY) { Utils.init() }
utilsJob.start()
utilsJob.await()
}
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
Log.i(TAG, "onCreate") Log.i(TAG, "onCreate")
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@@ -156,7 +172,11 @@ class MainActivity : FragmentActivity() {
} }
fun fragmentReady() { fun fragmentReady() {
mainFragment.fragmentReady() ready++
Log.i(TAG, "ready $ready")
if (ready == 4) {
mainFragment.fragmentReady()
}
} }
override fun onTouchEvent(event: MotionEvent?): Boolean { override fun onTouchEvent(event: MotionEvent?): Boolean {
@@ -496,7 +516,7 @@ class MainActivity : FragmentActivity() {
override fun onResume() { override fun onResume() {
Log.i(TAG, "onResume") Log.i(TAG, "onResume")
super.onResume() super.onResume()
if (!mainFragment.isHidden){ if (!mainFragment.isHidden) {
handler.postDelayed(hideMain, delayHideMain) handler.postDelayed(hideMain, delayHideMain)
} }
} }
@@ -42,8 +42,6 @@ class MainFragment : Fragment(), CardAdapter.ItemListener {
private val handler = Handler(Looper.getMainLooper()) private val handler = Handler(Looper.getMainLooper())
private lateinit var mUpdateProgramRunnable: UpdateProgramRunnable private lateinit var mUpdateProgramRunnable: UpdateProgramRunnable
private var ready = 0
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
@@ -149,7 +147,7 @@ class MainFragment : Fragment(), CardAdapter.ItemListener {
} }
} }
fragmentReady() (activity as MainActivity).fragmentReady()
} }
} }
@@ -180,6 +178,8 @@ class MainFragment : Fragment(), CardAdapter.ItemListener {
fun setPosition() { fun setPosition() {
val tvViewModel = tvListViewModel.getTVViewModel(itemPosition) val tvViewModel = tvListViewModel.getTVViewModel(itemPosition)
Log.i(TAG, "tvViewModel $tvViewModel")
Log.i(TAG, "rowList ${rowList.size}")
rowList[tvViewModel!!.getRowPosition()].post { rowList[tvViewModel!!.getRowPosition()].post {
((rowList[tvViewModel.getRowPosition()] as RecyclerView).layoutManager as LinearLayoutManager).findViewByPosition( ((rowList[tvViewModel.getRowPosition()] as RecyclerView).layoutManager as LinearLayoutManager).findViewByPosition(
tvViewModel.getItemPosition() tvViewModel.getItemPosition()
@@ -212,12 +212,8 @@ class MainFragment : Fragment(), CardAdapter.ItemListener {
} }
fun fragmentReady() { fun fragmentReady() {
ready++
Log.i(TAG, "ready $ready")
if (ready == 4) {
// request.fetchPage() // request.fetchPage()
tvListViewModel.getTVViewModel(itemPosition)?.changed() tvListViewModel.getTVViewModel(itemPosition)?.changed()
}
} }
fun play(itemPosition: Int) { fun play(itemPosition: Int) {
@@ -299,7 +295,9 @@ class MainFragment : Fragment(), CardAdapter.ItemListener {
override fun onDestroy() { override fun onDestroy() {
Log.i(TAG, "onDestroy") Log.i(TAG, "onDestroy")
super.onDestroy() super.onDestroy()
handler.removeCallbacks(mUpdateProgramRunnable) if (::mUpdateProgramRunnable.isInitialized) {
handler.removeCallbacks(mUpdateProgramRunnable)
}
} }
override fun onDestroyView() { override fun onDestroyView() {
@@ -32,7 +32,6 @@ class PlayerFragment : Fragment() {
): View { ): View {
_binding = PlayerBinding.inflate(inflater, container, false) _binding = PlayerBinding.inflate(inflater, container, false)
playerView = _binding!!.playerView playerView = _binding!!.playerView
(activity as MainActivity).playerFragment = this
playerView?.viewTreeObserver?.addOnGlobalLayoutListener(object : playerView?.viewTreeObserver?.addOnGlobalLayoutListener(object :
ViewTreeObserver.OnGlobalLayoutListener { ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() { override fun onGlobalLayout() {
@@ -86,6 +85,7 @@ class PlayerFragment : Fragment() {
if (playerView != null && playerView!!.player?.isPlaying == false) { if (playerView != null && playerView!!.player?.isPlaying == false) {
Log.i(TAG, "replay") Log.i(TAG, "replay")
playerView!!.player?.prepare() playerView!!.player?.prepare()
playerView!!.player?.play()
} else { } else {
Log.i(TAG, "playing") Log.i(TAG, "playing")
} }
@@ -364,7 +364,6 @@ class Request {
for ((_, v) in TVList.list) { for ((_, v) in TVList.list) {
for (v2 in v) { for (v2 in v) {
Log.i(TAG, "$v2")
if (v2.title == item.channelName || v2.alias == item.channelName) { if (v2.title == item.channelName || v2.alias == item.channelName) {
v2.pid = item.pid v2.pid = item.pid
v2.sid = item.streamId v2.sid = item.streamId
@@ -0,0 +1,101 @@
package com.lizongying.mytv
import android.app.DownloadManager
import android.app.DownloadManager.Request
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.util.Log
import androidx.annotation.RequiresApi
import com.lizongying.mytv.api.Release
import com.lizongying.mytv.requests.MyRequest
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.io.File
class UpdateManager(private var context: Context?) {
private var myRequest = MyRequest()
@RequiresApi(Build.VERSION_CODES.O)
fun checkAndUpdate() {
CoroutineScope(Dispatchers.Main).launch {
try {
val release = myRequest.getRelease()
// 在主线程中更新 UI
updateUI(release)
if (release?.data?.versionCode!! > 0) {
startDownload(release)
}
} catch (e: Exception) {
// 处理异常情况
Log.e(TAG, "Error occurred: ${e.message}", e)
}
}
}
private fun updateUI(release: Release?) {
}
@RequiresApi(Build.VERSION_CODES.O)
private fun startDownload(release: Release) {
val apkFileName = "my-tv-${release.data.versionName}.apk"
val downloadManager =
context!!.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
val request = Request(Uri.parse(release.data.downloadUrl))
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, apkFileName)
request.setTitle("New Version Download")
request.setNotificationVisibility(Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
// 获取下载任务的引用
val downloadReference = downloadManager.enqueue(request)
// 注册广播接收器,监听下载完成事件
context!!.registerReceiver(
DownloadReceiver(context!!, apkFileName, downloadReference),
IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE), Context.RECEIVER_NOT_EXPORTED
)
}
private class DownloadReceiver(
private val context: Context,
private val apkFileName: String,
private val downloadReference: Long
) : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val reference = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1)
// 检查是否是我们发起的下载
if (reference == downloadReference) {
// 下载完成,触发安装
installNewVersion()
}
}
private fun installNewVersion() {
val installIntent = Intent(Intent.ACTION_VIEW)
val apkUri = Uri.fromFile(
File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
apkFileName
)
)
installIntent.setDataAndType(apkUri, "application/vnd.android.package-archive")
installIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(installIntent)
}
}
companion object {
private const val TAG = "UpdateManager"
}
}
+49 -4
View File
@@ -3,18 +3,63 @@ package com.lizongying.mytv
import android.content.Context import android.content.Context
import android.content.res.Resources import android.content.res.Resources
import android.util.TypedValue import android.util.TypedValue
import com.google.gson.Gson
import com.lizongying.mytv.api.TimeResponse
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.File import java.io.File
import java.text.SimpleDateFormat
import java.util.*
import java.io.IOException import java.io.IOException
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
object Utils { object Utils {
private var between: Long = 0
fun getDateFormat(format: String): String { fun getDateFormat(format: String): String {
return SimpleDateFormat(format, Locale.CHINA).format(Date()) return SimpleDateFormat(
format,
Locale.CHINA
).format(Date(System.currentTimeMillis() - between))
} }
fun getDateTimestamp(): Long { fun getDateTimestamp(): Long {
return Date().time / 1000 return (System.currentTimeMillis() - between) / 1000
}
suspend fun init() {
var currentTimeMillis: Long = 0
try {
currentTimeMillis = getTimestampFromServer()
} catch (e: Exception) {
println("Failed to retrieve timestamp from server: ${e.message}")
}
between = System.currentTimeMillis() - currentTimeMillis
}
/**
* 从服务器获取时间戳
* @return Long 时间戳
*/
private suspend fun getTimestampFromServer(): Long {
return withContext(Dispatchers.IO) {
val client = okhttp3.OkHttpClient.Builder()
.connectTimeout(500, java.util.concurrent.TimeUnit.MILLISECONDS)
.readTimeout(1, java.util.concurrent.TimeUnit.SECONDS).build()
val request = okhttp3.Request.Builder()
.url("https://api.m.taobao.com/rest/api3.do?api=mtop.common.getTimestamp")
.build()
try {
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) throw IOException("Unexpected code $response")
val string = response.body()?.string()
Gson().fromJson(string, TimeResponse::class.java).data.t.toLong()
}
} catch (e: IOException) {
// Handle network errors
throw IOException("Error during network request", e)
}
}
} }
fun dpToPx(dp: Float): Int { fun dpToPx(dp: Float): Int {
@@ -34,6 +34,14 @@ class ApiClient {
.build().create(YSPTokenService::class.java) .build().create(YSPTokenService::class.java)
} }
val ReleaseService by lazy {
Retrofit.Builder()
.baseUrl(myUrl)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build().create(ReleaseService::class.java)
}
val yspProtoService: YSPProtoService by lazy { val yspProtoService: YSPProtoService by lazy {
Retrofit.Builder() Retrofit.Builder()
.baseUrl(protoUrl) .baseUrl(protoUrl)
@@ -3,9 +3,30 @@ package com.lizongying.mytv.api
data class Info( data class Info(
val code: Int?, val code: Int?,
val msg: String?, val msg: String?,
val data: InfoData, val data: Data,
) ) {
data class Data(
val token: String,
)
}
data class InfoData( data class Release(
val token: String, val code: Int?,
) val msg: String?,
val data: Data,
) {
data class Data(
val versionName: String,
val versionCode: Int,
val downloadUrl: String,
val updateTime: Int,
)
}
data class TimeResponse(
val data: Time
) {
data class Time(
val t: String
)
}
@@ -0,0 +1,11 @@
package com.lizongying.mytv.api
import retrofit2.Call
import retrofit2.http.GET
interface ReleaseService {
@GET("my-tv/v1/release")
fun getRelease(
): Call<Release>
}
@@ -0,0 +1,44 @@
package com.lizongying.mytv.requests
import com.lizongying.mytv.api.ApiClient
import com.lizongying.mytv.api.Release
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
class MyRequest {
private var releaseService = ApiClient().ReleaseService
suspend fun getRelease(): Release? {
return withContext(Dispatchers.IO) {
fetchRelease()
}
}
private suspend fun fetchRelease(): Release? {
return suspendCoroutine { continuation ->
releaseService.getRelease()
.enqueue(object : Callback<Release> {
override fun onResponse(call: Call<Release>, response: Response<Release>) {
if (response.isSuccessful) {
continuation.resume(response.body())
} else {
continuation.resume(null)
}
}
override fun onFailure(call: Call<Release>, t: Throwable) {
continuation.resume(null)
}
})
}
}
companion object {
private const val TAG = "MyRequest"
}
}