package com.assimilate.alltrans.curview import android.content.Context import android.graphics.Bitmap import android.graphics.PixelFormat import android.graphics.Rect import android.media.ImageReader import android.os.Build import android.os.Handler import android.os.Looper import android.util.Log import android.view.Gravity import android.view.LayoutInflater import android.view.MotionEvent import android.view.View import android.view.ViewGroup import android.view.WindowManager import com.assimilate.alltrans.MyApp import com.assimilate.alltrans.R import com.assimilate.alltrans.common.FirebaseAnalyticsHelper import com.assimilate.alltrans.common.Logger import com.assimilate.alltrans.common.MyTextTools import com.assimilate.alltrans.databinding.LayoutSusDistrictBinding import com.assimilate.alltrans.http.GoogleTranslator import com.assimilate.alltrans.http.Translator import com.assimilate.alltrans.model.LanguagesConstants import com.assimilate.alltrans.model.PreferenceLanguageUtils import com.google.mlkit.vision.common.InputImage import com.google.mlkit.vision.text.TextRecognition import com.google.mlkit.vision.text.chinese.ChineseTextRecognizerOptions import java.nio.ByteBuffer class DistrictView( private val context: Context ) { private lateinit var bindingSusDistrict: LayoutSusDistrictBinding private lateinit var districtView: View private lateinit var overlayView: View private val windowManager: WindowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager fun showDistrictView(imageReader: ImageReader, startX: Int, startY: Int, endX: Int, endY: Int) { // 添加一个全屏的透明背景视图 overlayView = View(context).apply { layoutParams = ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT ) setBackgroundColor(0x00000000) // 全透明 setOnTouchListener { _, event -> if (event.action == MotionEvent.ACTION_DOWN) { removeDistrictView() performClick() } true } } val overlayParams = WindowManager.LayoutParams( WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT, if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY } else { WindowManager.LayoutParams.TYPE_PHONE }, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN or WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS or WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR, PixelFormat.TRANSLUCENT ) windowManager.addView(overlayView, overlayParams) // 初始化 DistrictView bindingSusDistrict = LayoutSusDistrictBinding.inflate(LayoutInflater.from(context)) districtView = bindingSusDistrict.root val displayMetrics = context.resources.displayMetrics val screenWidth = displayMetrics.widthPixels val density = displayMetrics.density val marginDp = 16 val marginPx = (marginDp * density).toInt() val layoutParams = WindowManager.LayoutParams( WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT, if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY } else { WindowManager.LayoutParams.TYPE_PHONE }, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN or WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS or WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR, PixelFormat.TRANSLUCENT ) layoutParams.gravity = Gravity.TOP or Gravity.LEFT layoutParams.x = marginPx layoutParams.y = 100 layoutParams.width = screenWidth - 2 * marginPx layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT windowManager.addView(districtView, layoutParams) initDistrictClick() // 获取最新的图像并处理 val image = imageReader.acquireLatestImage() image?.let { val planes = it.planes if (planes.isNotEmpty()) { val buffer: ByteBuffer = planes[0].buffer val pixelStride: Int = planes[0].pixelStride val rowStride: Int = planes[0].rowStride val rowPadding: Int = rowStride - pixelStride * image.width // 从缓冲区创建位图 val bitmap = Bitmap.createBitmap( image.width + rowPadding / pixelStride, image.height, Bitmap.Config.ARGB_8888 ) bitmap.copyPixelsFromBuffer(buffer) // 根据用户框选区域裁剪位图 val rect = Rect(startX, startY, endX, endY) takeDistrictScreenshot(bitmap, rect) } image.close() } } private fun initDistrictClick() { bindingSusDistrict.ivSourceTts.setOnClickListener { val lanSourceCode = LanguagesConstants.getInstance().getLanguageCodeByLanguage( PreferenceLanguageUtils.getString("language_source"), MyApp.applicationContext() ) MyTextTools.ttsReadText( bindingSusDistrict.tvTrSource.text.toString(), lanSourceCode, context ) } bindingSusDistrict.ivTrCopy.setOnClickListener { MyTextTools.copyToClipboard(context, bindingSusDistrict.tvTrTarget.text.toString()) } bindingSusDistrict.ivTrTargetDic.setOnClickListener { if (bindingSusDistrict.tvTrTarget.text.toString().isNotEmpty()) { MyTextTools.makeWordsClickableWithUnderline( bindingSusDistrict.tvTrTarget, bindingSusDistrict.tvTrTarget.text.toString(), object : MyTextTools.OnWordClickListener { override fun onWordClick(word: String?) { Log.d("gvsdacd", "$word is clicked") } }) } } // bindingSusDistrict.ivTrTargetShare.setOnClickListener { // MyTextTools.shareText( // context, // bindingSusDistrict.tvTrTarget.text.toString() // ) // } bindingSusDistrict.ivTargetTts.setOnClickListener { val lanTargetCode = LanguagesConstants.getInstance().getLanguageCodeByLanguage( PreferenceLanguageUtils.getString("language_target"), MyApp.applicationContext() ) MyTextTools.ttsReadText( bindingSusDistrict.tvTrTarget.text.toString(), lanTargetCode, context ) } bindingSusDistrict.ivTrCollect.setOnClickListener { addCollect() } bindingSusDistrict.ivSourceClear.setOnClickListener { bindingSusDistrict.tvTrSource.text = "" bindingSusDistrict.tvTrTarget.text = "" removeDistrictView() } } fun removeDistrictView() { windowManager.removeView(districtView) windowManager.removeView(overlayView) } private fun takeDistrictScreenshot(image: Bitmap, rect: Rect) { if (rect.width() > 0 && rect.height() > 0) { val croppedBitmap = Bitmap.createBitmap( image, rect.left, rect.top, rect.width(), rect.height() ) val recognizer = TextRecognition.getClient(ChineseTextRecognizerOptions.Builder().build()) val imageNew = InputImage.fromBitmap(croppedBitmap, 0) recognizer.process(imageNew) .addOnSuccessListener { visionText -> bindingSusDistrict.tvTrSource.text = visionText.text // Add translation functionality here if needed translate(visionText.text) } .addOnFailureListener { e -> Log.e("DistrictView", "Text recognition failed", e) } } else { Log.e("DistrictView", "Rect width or height is 0") } } private fun addCollect() { // Add collect functionality here bindingSusDistrict.ivTrCollect.setImageResource(R.drawable.ic_like_yes) } private fun translate(text: String) { if (text.isEmpty()) { Logger.d("log", "translating(not post data)...") return } val lanSourceCode = LanguagesConstants.getInstance().getLanguageCodeByLanguage( PreferenceLanguageUtils.getString("language_source"), MyApp.applicationContext() ) val lanTargetCode = LanguagesConstants.getInstance().getLanguageCodeByLanguage( PreferenceLanguageUtils.getString("language_target"), MyApp.applicationContext() ) val param = HashMap().apply { put("sourceLanguage", lanSourceCode) put("translationLanguage", lanTargetCode) put("text", text) } Handler(Looper.getMainLooper()).post { bindingSusDistrict.tvTrTarget.text = "translating..." } val translator: Translator = GoogleTranslator() translator.translate(param, object : GoogleTranslator.GoogleTranslateCallback { override fun onResponse(result: String?, errorMessage: String?) { Handler(Looper.getMainLooper()).post { if (!result.isNullOrEmpty()) { bindingSusDistrict.tvTrTarget.text = result } else if (!errorMessage.isNullOrEmpty()) { Log.e("TranslationError", errorMessage) bindingSusDistrict.tvTrTarget.text = "Translation error: $errorMessage" } } } override fun onFailure(errorMessage: String?) { Handler(Looper.getMainLooper()).post { FirebaseAnalyticsHelper.hoverDistrictResultEvent( MyApp.Config.FAIL_REASON, "district" + errorMessage.toString() ) bindingSusDistrict.tvTrTarget.text = "Translation failed: $errorMessage" } } }) } }