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? = 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" } }