347 lines
11 KiB
Kotlin
347 lines
11 KiB
Kotlin
package com.lizongying.mytv
|
|
|
|
import android.app.AlertDialog
|
|
import android.content.pm.PackageInfo
|
|
import android.content.pm.PackageManager
|
|
import android.content.pm.Signature
|
|
import android.content.pm.SigningInfo
|
|
import android.os.Build
|
|
import android.os.Bundle
|
|
import android.os.Handler
|
|
import android.os.Looper
|
|
import android.util.Log
|
|
import android.view.GestureDetector
|
|
import android.view.KeyEvent
|
|
import android.view.MotionEvent
|
|
import android.view.WindowManager
|
|
import android.widget.ImageView
|
|
import android.widget.LinearLayout
|
|
import android.widget.TextView
|
|
import android.widget.Toast
|
|
import androidx.core.content.ContextCompat
|
|
import androidx.fragment.app.FragmentActivity
|
|
import com.lizongying.mytv.models.TVViewModel
|
|
import java.security.MessageDigest
|
|
|
|
|
|
class MainActivity : FragmentActivity() {
|
|
|
|
private val playbackFragment = PlaybackFragment()
|
|
private val mainFragment = MainFragment()
|
|
private val infoFragment = InfoFragment()
|
|
|
|
private var doubleBackToExitPressedOnce = false
|
|
|
|
private lateinit var gestureDetector: GestureDetector
|
|
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
super.onCreate(savedInstanceState)
|
|
setContentView(R.layout.activity_main)
|
|
|
|
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
|
window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
|
|
|
|
if (savedInstanceState == null) {
|
|
supportFragmentManager.beginTransaction()
|
|
.add(R.id.main_browse_fragment, playbackFragment)
|
|
.add(R.id.main_browse_fragment, mainFragment)
|
|
.add(R.id.main_browse_fragment, infoFragment)
|
|
.hide(infoFragment)
|
|
.commit()
|
|
}
|
|
gestureDetector = GestureDetector(this, GestureListener())
|
|
}
|
|
|
|
fun switchInfoFragment(tv: TV) {
|
|
infoFragment.setInfo(tv)
|
|
|
|
if (infoFragment.isHidden) {
|
|
supportFragmentManager.beginTransaction().show(infoFragment).commit()
|
|
}
|
|
}
|
|
|
|
fun showInfoFragment(tv: TV) {
|
|
infoFragment.setInfo(tv)
|
|
supportFragmentManager.beginTransaction()
|
|
.show(infoFragment)
|
|
.commit()
|
|
}
|
|
|
|
fun hideInfoFragment() {
|
|
supportFragmentManager.beginTransaction()
|
|
.hide(infoFragment)
|
|
.commit()
|
|
}
|
|
|
|
fun play(tvViewModel: TVViewModel) {
|
|
Log.i(TAG, "play: ${tvViewModel.getTV()}")
|
|
playbackFragment.play(tvViewModel)
|
|
}
|
|
|
|
fun prev() {
|
|
mainFragment.prev()
|
|
}
|
|
|
|
fun next() {
|
|
mainFragment.next()
|
|
}
|
|
|
|
fun prevSource() {
|
|
mainFragment.prevSource()
|
|
}
|
|
|
|
fun nextSource() {
|
|
mainFragment.nextSource()
|
|
}
|
|
|
|
fun switchMainFragment() {
|
|
val transaction = supportFragmentManager.beginTransaction()
|
|
|
|
if (mainFragment.isHidden) {
|
|
focusMainFragment()
|
|
transaction.show(mainFragment)
|
|
} else {
|
|
transaction.hide(mainFragment)
|
|
}
|
|
|
|
transaction.commit()
|
|
}
|
|
|
|
private fun focusMainFragment() {
|
|
mainFragment.focus()
|
|
}
|
|
|
|
fun mainFragmentIsHidden(): Boolean {
|
|
return mainFragment.isHidden
|
|
}
|
|
|
|
private fun hideMainFragment() {
|
|
if (!mainFragment.isHidden) {
|
|
supportFragmentManager.beginTransaction()
|
|
.hide(mainFragment)
|
|
.commit()
|
|
}
|
|
}
|
|
|
|
override fun onTouchEvent(event: MotionEvent?): Boolean {
|
|
// 在触摸事件中将事件传递给 GestureDetector 处理手势
|
|
if (event != null) {
|
|
gestureDetector.onTouchEvent(event)
|
|
}
|
|
return super.onTouchEvent(event)
|
|
}
|
|
|
|
private inner class GestureListener : GestureDetector.SimpleOnGestureListener() {
|
|
|
|
override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
|
|
switchMainFragment()
|
|
return true
|
|
}
|
|
|
|
override fun onFling(
|
|
e1: MotionEvent,
|
|
e2: MotionEvent,
|
|
velocityX: Float,
|
|
velocityY: Float
|
|
): Boolean {
|
|
// 如果 Y 方向的速度为负值,表示向上滑动
|
|
if (velocityY < 0) {
|
|
// 在这里执行上滑时的操作
|
|
if (mainFragment.isHidden) {
|
|
prev()
|
|
} else {
|
|
if (mainFragment.selectedPosition == 0) {
|
|
mainFragment.setSelectedPosition(
|
|
mainFragment.tvListViewModel.maxNum.size - 1,
|
|
false
|
|
)
|
|
}
|
|
}
|
|
}
|
|
if (velocityY > 0) {
|
|
// 在这里执行上滑时的操作
|
|
if (mainFragment.isHidden) {
|
|
next()
|
|
} else {
|
|
if (mainFragment.selectedPosition == mainFragment.tvListViewModel.maxNum.size - 1) {
|
|
// mainFragment.setSelectedPosition(0, false)
|
|
hideMainFragment()
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
return super.onFling(e1, e2, velocityX, velocityY)
|
|
}
|
|
}
|
|
|
|
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
|
|
when (keyCode) {
|
|
KeyEvent.KEYCODE_BACK -> {
|
|
if (!mainFragmentIsHidden()) {
|
|
hideMainFragment()
|
|
return true
|
|
}
|
|
|
|
if (doubleBackToExitPressedOnce) {
|
|
super.onBackPressed()
|
|
return true
|
|
}
|
|
|
|
this.doubleBackToExitPressedOnce = true
|
|
Toast.makeText(this, "再按一次退出", Toast.LENGTH_SHORT).show()
|
|
|
|
Handler(Looper.getMainLooper()).postDelayed({
|
|
doubleBackToExitPressedOnce = false
|
|
}, 2000)
|
|
return true
|
|
}
|
|
|
|
KeyEvent.KEYCODE_MENU -> {
|
|
val versionName = getPackageInfo().versionName
|
|
|
|
val textView = TextView(this)
|
|
textView.text =
|
|
"当前版本: $versionName\n获取最新: https://github.com/lizongying/my-tv/releases/"
|
|
|
|
val imageView = ImageView(this)
|
|
val drawable = ContextCompat.getDrawable(this, R.drawable.appreciate)
|
|
imageView.setImageDrawable(drawable)
|
|
|
|
val linearLayout = LinearLayout(this)
|
|
linearLayout.orientation = LinearLayout.VERTICAL
|
|
linearLayout.addView(textView)
|
|
linearLayout.addView(imageView)
|
|
|
|
val layoutParams = LinearLayout.LayoutParams(
|
|
LinearLayout.LayoutParams.MATCH_PARENT,
|
|
LinearLayout.LayoutParams.WRAP_CONTENT
|
|
)
|
|
imageView.layoutParams = layoutParams
|
|
textView.layoutParams = layoutParams
|
|
|
|
val builder: AlertDialog.Builder = AlertDialog.Builder(this)
|
|
builder
|
|
.setView(linearLayout)
|
|
|
|
val dialog: AlertDialog = builder.create()
|
|
dialog.show()
|
|
return true
|
|
}
|
|
|
|
KeyEvent.KEYCODE_DPAD_CENTER -> {
|
|
Log.i(TAG, "KEYCODE_DPAD_CENTER")
|
|
// if (mainFragment.isHidden) {
|
|
// mainFragment.checkProgram()
|
|
// }
|
|
switchMainFragment()
|
|
}
|
|
|
|
KeyEvent.KEYCODE_DPAD_UP -> {
|
|
if (mainFragment.isHidden) {
|
|
prev()
|
|
} else {
|
|
if (mainFragment.selectedPosition == 0) {
|
|
mainFragment.setSelectedPosition(
|
|
mainFragment.tvListViewModel.maxNum.size - 1,
|
|
false
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
KeyEvent.KEYCODE_DPAD_DOWN -> {
|
|
if (mainFragment.isHidden) {
|
|
next()
|
|
} else {
|
|
if (mainFragment.selectedPosition == mainFragment.tvListViewModel.maxNum.size - 1) {
|
|
// mainFragment.setSelectedPosition(0, false)
|
|
hideMainFragment()
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
|
|
KeyEvent.KEYCODE_DPAD_LEFT -> {
|
|
if (mainFragment.isHidden) {
|
|
prevSource()
|
|
} else {
|
|
if (mainFragment.tvListViewModel.getTVViewModelCurrent()
|
|
?.getItemPosition() == 0
|
|
) {
|
|
// mainFragment.toLastPosition()
|
|
hideMainFragment()
|
|
}
|
|
}
|
|
}
|
|
|
|
KeyEvent.KEYCODE_DPAD_RIGHT -> {
|
|
if (mainFragment.isHidden) {
|
|
nextSource()
|
|
} else {
|
|
if (mainFragment.tvListViewModel.getTVViewModelCurrent()
|
|
?.getItemPosition() == mainFragment.tvListViewModel.maxNum[mainFragment.selectedPosition] - 1
|
|
) {
|
|
mainFragment.toFirstPosition()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return super.onKeyDown(keyCode, event)
|
|
}
|
|
|
|
private fun getPackageInfo(): PackageInfo {
|
|
val flag = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
|
|
PackageManager.GET_SIGNATURES
|
|
} else {
|
|
PackageManager.GET_SIGNING_CERTIFICATES
|
|
}
|
|
|
|
return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
|
|
packageManager.getPackageInfo(packageName, flag)
|
|
} else {
|
|
packageManager.getPackageInfo(
|
|
packageName,
|
|
PackageManager.PackageInfoFlags.of(PackageManager.GET_SIGNING_CERTIFICATES.toLong())
|
|
)
|
|
}
|
|
}
|
|
|
|
private fun getAppSignature(): String {
|
|
val packageInfo = getPackageInfo()
|
|
|
|
var sign: Signature? = null
|
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
|
|
val signatures: Array<out Signature>? = packageInfo.signatures
|
|
if (signatures != null) {
|
|
sign = signatures[0]
|
|
}
|
|
} else {
|
|
val signingInfo: SigningInfo? = packageInfo.signingInfo
|
|
if (signingInfo != null) {
|
|
sign = signingInfo.apkContentsSigners[0]
|
|
}
|
|
}
|
|
if (sign == null) {
|
|
return ""
|
|
}
|
|
|
|
return hashSignature(sign)
|
|
}
|
|
|
|
private fun hashSignature(signature: Signature): String {
|
|
return try {
|
|
val md = MessageDigest.getInstance("SHA-256")
|
|
md.update(signature.toByteArray())
|
|
val digest = md.digest()
|
|
digest.let { it -> it.joinToString("") { "%02x".format(it) } }
|
|
} catch (e: Exception) {
|
|
Log.e(TAG, "Error hashing signature", e)
|
|
""
|
|
}
|
|
}
|
|
|
|
companion object {
|
|
private const val TAG = "MainActivity"
|
|
}
|
|
} |