package com.sw.platecabinet.activity import android.content.Context import android.content.Intent import android.os.Build import android.os.Bundle import android.text.TextUtils import android.view.View import android.view.WindowInsetsController import android.view.WindowManager import android.widget.TextView import androidx.activity.enableEdgeToEdge import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity import androidx.core.view.WindowCompat import androidx.lifecycle.lifecycleScope import androidx.viewbinding.ViewBinding import com.sw.inbound.utils.DateTimeUtils import com.sw.plate.App import com.sw.plate.utils.Base64 import com.sw.plate.utils.arcface.facedb.FaceDatabase import com.sw.plate.utils.arcface.facedb.entity.FaceEntity import com.sw.plate.utils.arcface.viewmodel.RecognizeViewModel import com.sw.platecabinet.R import com.sw.platecabinet.databinding.ItemTitleTimeBinding import com.sw.platecabinet.ext.clickWithCoroutines import com.sw.platecabinet.utils.IntervalExecutor import com.sw.platecabinet.utils.SpTool import com.sw.platecabinet.view.CustomLoadingDialog import com.sw.platecabinet.viewmodel.NetViewModelV2 import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import timber.log.Timber /** * activity 基类 */ abstract class BaseActivity : AppCompatActivity() { protected lateinit var binding: VB private var headerBinding: ItemTitleTimeBinding? = null protected lateinit var context: Context private var timeJob: Job? = null private var mDialogWaiting: CustomLoadingDialog? = null // private val permissionHelpers = mutableMapOf() // protected var keyEventHelper: ScanGunKeyEventHelper? = null public val recognizeViewModel by viewModels() public val netViewModelV2 by viewModels() private var startTime: Long = 0 override fun onCreate(savedInstanceState: Bundle?) { startTime = System.currentTimeMillis() super.onCreate(savedInstanceState) enableEdgeToEdge() context = this disableSystemUICompletely() // 确保内容延伸到导航栏区域 WindowCompat.setDecorFitsSystemWindows(window, false) //保持亮屏 window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) binding = inflateViewBinding() headerBinding = inflateTitleBinding() setContentView(binding.root) updateTime() registerDataChange() initialize() // registerKeyEvent() val durationTime = System.currentTimeMillis() - startTime Timber.d("启动时间:$durationTime") } // /** // * 监听扫描枪扫描事件 // */ // protected fun registerKeyEvent() { // keyEventHelper = // ScanGunKeyEventHelper(context, object : ScanGunKeyEventHelper.OnScanSuccessListener { // override fun onScanSuccess(barcode: String?) { // Timber.d("onScanSuccess barcode = $barcode") // if (barcode == null) return // handleScanKeyInfo(barcode) // } // }) // } /** * 处理扫描枪数据 */ protected open fun handleScanKeyInfo(scanInfo: String) { //// settingViewModel.findByPlateNumber(plateNumber = scanInfo) // var plateNumber = scanInfo // if (scanInfo.length > 6) { // plateNumber = scanInfo.take(6) // } // Log.d("TAG", "handleScanKeyInfo: " + Gson().toJson(MyApp.plateList)) // if (MyApp.plateList == null) { // initPlateList() // } // //柜子未关联该餐盘,直接找空位置放入盘子 // val item = MyApp.plateList?.firstOrNull { it.plateNumber.isNullOrBlank() } // if (item == null) { // //柜子已满 // MainActivity.start(context = context, pageType = PageType.PLATE_CABINET_FULL) // return // } // //找到位置,放入餐盘,清除已有id和时间 // item.plateNumber = plateNumber // item.faceId = null // item.updateTime = null // PlateUtils.open(this, item.equipmentBoxCode, true) // SpTool.savePlateData(MyApp.plateList!!) } // override fun dispatchKeyEvent(event: KeyEvent): Boolean { // if (keyEventHelper != null) { // if (keyEventHelper!!.isScanGunEvent(event)) { // keyEventHelper!!.analysisKeyEvent(event) // return true // } // } // return super.dispatchKeyEvent(event) // } fun updateTime() { headerBinding?.let { it.tvLeftDate.clickWithCoroutines( onDoubleClick = { onLeftDoubleClick() } ) it.tvRightTime.clickWithCoroutines( onDoubleClick = { onRightDoubleClick() } ) timeJob = lifecycleScope.launch { DateTimeUtils.realTimeChineseDateFlow() .collect { date -> it.tvRightTime.text = date } } } } /** * 左侧日期双击 */ open fun onLeftDoubleClick() { } /** * 右侧时间双击 */ open fun onRightDoubleClick() { //MainActivity.start(context, pageType = PageType.SETTING_LIST) } // override fun onRequestPermissionsResult( // requestCode: Int, // permissions: Array, // grantResults: IntArray // ) { // super.onRequestPermissionsResult(requestCode, permissions, grantResults) // // val helper = permissionHelpers[requestCode] // val allGranted = PermissionHelper.handlePermissionResult( // this, // requestCode, // permissions, // grantResults, // permissionHelper = helper // ) // // if (allGranted) { // permissionHelpers.remove(requestCode) // } // } // // /** // * 注册PermissionHelper以便处理结果 // */ // fun registerPermissionHelper(helper: PermissionHelper) { // permissionHelpers[helper.requestCode] = helper // } override fun onResume() { super.onResume() // 关键点2:防止某些场景下系统栏恢复 enforceImmersiveMode() } override fun onWindowFocusChanged(hasFocus: Boolean) { super.onWindowFocusChanged(hasFocus) if (hasFocus) { disableSystemUICompletely() } } private fun disableSystemUICompletely() { Timber.d("disableSystemUICompletely") // 禁用系统手势(Android 10+) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { window.insetsController?.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE } // 全屏+隐藏导航栏(所有版本通用) window.decorView.systemUiVisibility = ( View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_STABLE ) // 禁止窗口扩展至系统栏区域(彻底锁定) window.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS) window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) } private fun enforceImmersiveMode() { Timber.d("enforceImmersiveMode") // 持续强制隐藏系统栏(防止手势触发) window.decorView.postDelayed({ window.decorView.systemUiVisibility = ( View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY ) }, 100) // 延迟100ms确保覆盖手势触发 } /** * 显示等待提示框 */ fun showWaitingDialog(tip: String?) { runOnUiThread { hideWaitingDialog() val view = View.inflate(this, R.layout.dialog_waiting, null) if (!TextUtils.isEmpty(tip)) (view.findViewById(R.id.tvTip) as TextView).setText( tip ) mDialogWaiting = CustomLoadingDialog(this, view, R.style.MyDialog) mDialogWaiting!!.show() mDialogWaiting!!.setCancelable(true) mDialogWaiting!!.setCanceledOnTouchOutside(true) } } /** * 隐藏等待提示框 */ fun hideWaitingDialog() { runOnUiThread { mDialogWaiting?.dismiss() mDialogWaiting = null } } protected abstract fun inflateViewBinding(): VB protected abstract fun inflateTitleBinding(): ItemTitleTimeBinding? protected abstract fun initialize() /** * 注册数据监听 */ protected open fun registerDataChange() { Timber.d("registerDataChange") } override fun onDestroy() { timeJob?.cancel() // keyEventHelper?.onDestroy() super.onDestroy() } private val intervalExecutor by lazy { IntervalExecutor() } private var faceTaskJob: Job? = null // private val initialDelay = 5 * 60 * 1000L // private val dealyMillis = 10 * 60 * 1000L private val initialDelay = 1 * 1000L private val dealyMillis = 10 * 1000L fun startFaceTask() { faceTaskJob = intervalExecutor.startIntervalTaskWithInitialDelay(initialDelay, dealyMillis) { getFaceIncrementList() } } private var faceTimestamp = 0L //private var taskPageNo = 1 private fun getFaceIncrementList(pageNo: Int = 1) { val timestamp = SpTool.lastFaceTimestamp netViewModelV2.getFaceIncrementList( pageNo = pageNo, timestamp = timestamp ) { recognizeViewModel.refreshFaceList() } } fun clearAllFace(block: () -> Unit) { lifecycleScope.launch(Dispatchers.IO) { val faceDao = FaceDatabase.getInstance(App.getContext()).faceDao() faceDao.deleteAll() faceDao.resetId() recognizeViewModel.refreshFaceList() withContext(Dispatchers.Main) { block() } } } private var permissionCallback: ((isGranted: Boolean) -> Unit)? = null private var activityCallback: ((intent: Intent?) -> Unit)? = null fun requestPermission(permission: String, callback: (isGranted: Boolean) -> Unit) { this.permissionCallback = callback requestPermissionLauncher.launch(permission) } // 权限请求回调 val requestPermissionLauncher = registerForActivityResult( ActivityResultContracts.RequestPermission() ) { isGranted -> permissionCallback?.invoke(isGranted) } fun startActivity(intent: Intent, callback: (Intent?) -> Unit) { this.activityCallback = callback startActivityLauncher.launch(intent) } // activity页面返回的回调 private val startActivityLauncher = registerForActivityResult( ActivityResultContracts.StartActivityForResult() ) { activityCallback?.invoke(it.data) } }