diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 184028e..6d7aba8 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -90,9 +90,6 @@
-
diff --git a/app/src/main/java/com/nova/brain/glass/helper/OfflineCmdServiceHelper.kt b/app/src/main/java/com/nova/brain/glass/helper/OfflineCmdServiceHelper.kt
index 9c43023..f34a6fb 100644
--- a/app/src/main/java/com/nova/brain/glass/helper/OfflineCmdServiceHelper.kt
+++ b/app/src/main/java/com/nova/brain/glass/helper/OfflineCmdServiceHelper.kt
@@ -45,14 +45,7 @@ object OfflineCmdServiceHelper {
)
private val CMDS_SPRAYING = listOf(
OfflineCmdBean("开始", "kai shi"),
- OfflineCmdBean("开始任务", "kai shi ren wu"),
- OfflineCmdBean("拍照", "pai zhao"),
- OfflineCmdBean("拍摄", "pai she"),
- OfflineCmdBean("放大", "fang da"),
- OfflineCmdBean("拉近", "la jin"),
- OfflineCmdBean("缩小", "suo xiao"),
- OfflineCmdBean("拉远", "la yuan"),
- OfflineCmdBean("取消", "qu xiao")
+ OfflineCmdBean("开始任务", "kai shi ren wu")
)
private val CMDS_SPRAYING_FINISH = listOf(
OfflineCmdBean("补充照片", "bu chong zhao pian"),
diff --git a/app/src/main/java/com/nova/brain/glass/ui/CameraPreviewPocActivity.kt b/app/src/main/java/com/nova/brain/glass/ui/CameraPreviewPocActivity.kt
deleted file mode 100644
index c5a3ff6..0000000
--- a/app/src/main/java/com/nova/brain/glass/ui/CameraPreviewPocActivity.kt
+++ /dev/null
@@ -1,407 +0,0 @@
-package com.nova.brain.glass.ui
-
-import android.Manifest
-import android.content.Intent
-import android.content.pm.PackageManager
-import android.graphics.ImageFormat
-import android.graphics.Rect
-import android.graphics.SurfaceTexture
-import android.hardware.camera2.CameraCaptureSession
-import android.hardware.camera2.CameraCharacteristics
-import android.hardware.camera2.CameraAccessException
-import android.hardware.camera2.CameraDevice
-import android.hardware.camera2.CameraManager
-import android.hardware.camera2.CaptureRequest
-import android.hardware.camera2.TotalCaptureResult
-import android.hardware.camera2.params.StreamConfigurationMap
-import android.media.ImageReader
-import android.os.Bundle
-import android.os.Environment
-import android.os.Handler
-import android.os.HandlerThread
-import android.view.KeyEvent
-import android.view.Surface
-import android.view.TextureView
-import androidx.core.app.ActivityCompat
-import com.nova.brain.glass.R
-import com.nova.brain.glass.databinding.ActivityCameraPreviewPocBinding
-import com.nova.brain.glass.helper.OfflineCmdListener
-import com.nova.brain.glass.helper.OfflineCmdServiceHelper
-import com.xuqm.base.extensions.showMessage
-import com.xuqm.base.ui.BaseActivity
-import java.io.File
-import java.io.FileOutputStream
-import java.util.UUID
-import kotlin.math.roundToInt
-
-class CameraPreviewPocActivity : BaseActivity() {
-
- companion object {
- const val EXTRA_PHOTO_PATH = "extra_photo_path"
- private const val REQUEST_CAMERA_PERMISSION = 1001
- }
-
- override fun getLayoutId(): Int = R.layout.activity_camera_preview_poc
- override fun fullscreen(): Boolean = true
-
- private val cameraManager by lazy { getSystemService(CameraManager::class.java) }
- private var cameraDevice: CameraDevice? = null
- private var captureSession: CameraCaptureSession? = null
- private var previewRequestBuilder: CaptureRequest.Builder? = null
- private var imageReader: ImageReader? = null
- private var backgroundThread: HandlerThread? = null
- private var backgroundHandler: Handler? = null
- private var activeArraySize: Rect? = null
- private var maxZoom = 1f
- private var zoomLevel = 1f
- private var currentOutputPath: String? = null
- private var isCapturing = false
-
- private val offlineCmdListener = object : OfflineCmdListener {
- override fun onOfflineCmd(cmd: String) {
- runOnUiThread {
- when (cmd) {
- "退出", "返回", "退回", "取消" -> finish()
- "拍照", "拍摄", "开始", "开始任务" -> captureStillImage()
- "放大", "拉近" -> adjustZoom(0.2f)
- "缩小", "拉远" -> adjustZoom(-0.2f)
- }
- }
- }
- }
-
- private val textureListener = object : TextureView.SurfaceTextureListener {
- override fun onSurfaceTextureAvailable(surface: SurfaceTexture, width: Int, height: Int) {
- openCamera()
- }
-
- override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture, width: Int, height: Int) = Unit
- override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean = true
- override fun onSurfaceTextureUpdated(surface: SurfaceTexture) = Unit
- }
-
- override fun initView(savedInstanceState: Bundle?) {
- super.initView(savedInstanceState)
- binding.previewView.surfaceTextureListener = textureListener
- binding.captureButton.setOnClickListener { captureStillImage() }
- binding.zoomInButton.setOnClickListener { adjustZoom(0.2f) }
- binding.zoomOutButton.setOnClickListener { adjustZoom(-0.2f) }
- updateZoomText()
- }
-
- override fun onResume() {
- super.onResume()
- startBackgroundThread()
- OfflineCmdServiceHelper.addOnLineListener(offlineCmdListener)
- OfflineCmdServiceHelper.addListenerSpraying()
- if (binding.previewView.isAvailable) {
- openCamera()
- } else {
- binding.previewView.surfaceTextureListener = textureListener
- }
- }
-
- override fun onPause() {
- closeCamera()
- OfflineCmdServiceHelper.removeListenerSpraying()
- OfflineCmdServiceHelper.removeOnLineListener(offlineCmdListener)
- stopBackgroundThread()
- super.onPause()
- }
-
- override fun dispatchKeyEvent(event: KeyEvent): Boolean {
- if (event.action != KeyEvent.ACTION_DOWN) return super.dispatchKeyEvent(event)
- return when (event.keyCode) {
- KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_MINUS, KeyEvent.KEYCODE_VOLUME_DOWN -> {
- adjustZoom(-0.2f)
- true
- }
- KeyEvent.KEYCODE_DPAD_RIGHT, KeyEvent.KEYCODE_EQUALS, KeyEvent.KEYCODE_VOLUME_UP -> {
- adjustZoom(0.2f)
- true
- }
- KeyEvent.KEYCODE_DPAD_CENTER, KeyEvent.KEYCODE_ENTER, KeyEvent.KEYCODE_CAMERA -> {
- captureStillImage()
- true
- }
- else -> super.dispatchKeyEvent(event)
- }
- }
-
- override fun onRequestPermissionsResult(
- requestCode: Int,
- permissions: Array,
- grantResults: IntArray
- ) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults)
- if (requestCode != REQUEST_CAMERA_PERMISSION) return
- if (grantResults.all { it == PackageManager.PERMISSION_GRANTED }) {
- openCamera()
- } else {
- "缺少相机权限,无法验证预览".showMessage()
- finish()
- }
- }
-
- private fun openCamera() {
- if (
- ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED
- ) {
- ActivityCompat.requestPermissions(
- this,
- arrayOf(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO),
- REQUEST_CAMERA_PERMISSION
- )
- return
- }
- try {
- val selectedCameraId = selectBackCameraId() ?: run {
- "未找到可用相机".showMessage()
- finish()
- return
- }
- val characteristics = cameraManager.getCameraCharacteristics(selectedCameraId)
- activeArraySize = characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE)
- maxZoom = (characteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM) ?: 1f)
- .coerceAtLeast(1f)
- zoomLevel = zoomLevel.coerceIn(1f, maxZoom)
- val streamMap = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
- val previewSize = choosePreviewSize(streamMap)
- val captureSize = chooseCaptureSize(streamMap)
- val texture = binding.previewView.surfaceTexture ?: return
- texture.setDefaultBufferSize(previewSize.width, previewSize.height)
- imageReader?.close()
- imageReader = ImageReader.newInstance(captureSize.width, captureSize.height, ImageFormat.JPEG, 2).apply {
- setOnImageAvailableListener({ reader ->
- val image = reader.acquireNextImage() ?: return@setOnImageAvailableListener
- val outputPath = currentOutputPath
- if (outputPath == null) {
- image.close()
- return@setOnImageAvailableListener
- }
- val buffer = image.planes.firstOrNull()?.buffer
- val bytes = ByteArray(buffer?.remaining() ?: 0)
- buffer?.get(bytes)
- image.close()
- runCatching {
- FileOutputStream(outputPath).use { it.write(bytes) }
- }.onSuccess {
- runOnUiThread {
- setResult(RESULT_OK, Intent().putExtra(EXTRA_PHOTO_PATH, outputPath))
- finish()
- }
- }.onFailure {
- isCapturing = false
- runOnUiThread {
- binding.statusText.text = "图片保存失败: ${it.message ?: "未知错误"}"
- }
- }
- }, backgroundHandler)
- }
- binding.statusText.text = "相机预览验证中,可拉近拉远后拍照"
- cameraManager.openCamera(selectedCameraId, object : CameraDevice.StateCallback() {
- override fun onOpened(device: CameraDevice) {
- cameraDevice = device
- createPreviewSession(texture)
- }
-
- override fun onDisconnected(device: CameraDevice) {
- device.close()
- cameraDevice = null
- runOnUiThread { binding.statusText.text = "相机已断开" }
- }
-
- override fun onError(device: CameraDevice, error: Int) {
- device.close()
- cameraDevice = null
- runOnUiThread { binding.statusText.text = "相机打开失败: $error" }
- }
- }, backgroundHandler)
- } catch (securityException: SecurityException) {
- binding.statusText.text = "缺少相机权限"
- "缺少相机权限,无法打开预览".showMessage()
- }
- }
-
- private fun createPreviewSession(texture: SurfaceTexture) {
- val device = cameraDevice ?: return
- val previewSurface = Surface(texture)
- previewRequestBuilder = try {
- device.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW).apply {
- addTarget(previewSurface)
- set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO)
- set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE)
- applyZoom(this)
- }
- } catch (e: CameraAccessException) {
- handleCameraFailure("相机预览初始化失败: ${e.message}")
- return
- } catch (e: IllegalStateException) {
- handleCameraFailure("相机设备不可用: ${e.message}")
- return
- }
- val readerSurface = imageReader?.surface ?: return
- try {
- device.createCaptureSession(
- listOf(previewSurface, readerSurface),
- object : CameraCaptureSession.StateCallback() {
- override fun onConfigured(session: CameraCaptureSession) {
- captureSession = session
- val request = previewRequestBuilder?.build() ?: return
- try {
- session.setRepeatingRequest(request, null, backgroundHandler)
- } catch (e: CameraAccessException) {
- handleCameraFailure("相机预览启动失败: ${e.message}")
- } catch (e: IllegalStateException) {
- handleCameraFailure("相机会话不可用: ${e.message}")
- }
- }
-
- override fun onConfigureFailed(session: CameraCaptureSession) {
- handleCameraFailure("相机预览配置失败")
- }
- },
- backgroundHandler
- )
- } catch (e: CameraAccessException) {
- handleCameraFailure("相机会话创建失败: ${e.message}")
- } catch (e: IllegalStateException) {
- handleCameraFailure("相机会话不可用: ${e.message}")
- }
- }
-
- private fun captureStillImage() {
- if (isCapturing) return
- val device = cameraDevice ?: return
- val session = captureSession ?: return
- val readerSurface = imageReader?.surface ?: return
- val outputPath = createOutputFile().absolutePath
- currentOutputPath = outputPath
- isCapturing = true
- binding.statusText.text = "拍照中,请保持稳定..."
- try {
- val captureBuilder = device.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE).apply {
- addTarget(readerSurface)
- set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO)
- set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE)
- applyZoom(this)
- set(CaptureRequest.JPEG_ORIENTATION, 0)
- }
- session.stopRepeating()
- session.capture(captureBuilder.build(), object : CameraCaptureSession.CaptureCallback() {
- override fun onCaptureCompleted(
- session: CameraCaptureSession,
- request: CaptureRequest,
- result: TotalCaptureResult
- ) {
- previewRequestBuilder?.build()?.let {
- runCatching {
- session.setRepeatingRequest(it, null, backgroundHandler)
- }
- }
- }
- }, backgroundHandler)
- } catch (e: CameraAccessException) {
- isCapturing = false
- handleCameraFailure("拍照失败: ${e.message}")
- } catch (e: IllegalStateException) {
- isCapturing = false
- handleCameraFailure("相机设备不可用: ${e.message}")
- }
- }
-
- private fun adjustZoom(delta: Float) {
- maxZoom = maxZoom.coerceAtLeast(1f)
- zoomLevel = (zoomLevel + delta).coerceIn(1f, maxZoom)
- updateZoomText()
- val requestBuilder = previewRequestBuilder ?: return
- val session = captureSession ?: return
- applyZoom(requestBuilder)
- try {
- session.setRepeatingRequest(requestBuilder.build(), null, backgroundHandler)
- } catch (e: CameraAccessException) {
- handleCameraFailure("缩放失败: ${e.message}")
- } catch (e: IllegalStateException) {
- handleCameraFailure("相机会话不可用: ${e.message}")
- }
- }
-
- private fun updateZoomText() {
- binding.zoomText.text = "缩放 ${String.format("%.1f", zoomLevel)}x"
- }
-
- private fun applyZoom(builder: CaptureRequest.Builder) {
- val sensorRect = activeArraySize ?: return
- if (zoomLevel <= 1f) {
- builder.set(CaptureRequest.SCALER_CROP_REGION, sensorRect)
- return
- }
- val centerX = sensorRect.centerX()
- val centerY = sensorRect.centerY()
- val deltaX = (0.5f * sensorRect.width() / zoomLevel).roundToInt()
- val deltaY = (0.5f * sensorRect.height() / zoomLevel).roundToInt()
- val cropRect = Rect(centerX - deltaX, centerY - deltaY, centerX + deltaX, centerY + deltaY)
- builder.set(CaptureRequest.SCALER_CROP_REGION, cropRect)
- }
-
- private fun selectBackCameraId(): String? {
- val ids = cameraManager.cameraIdList ?: return null
- return ids.firstOrNull { id ->
- val facing = cameraManager.getCameraCharacteristics(id)
- .get(CameraCharacteristics.LENS_FACING)
- facing == CameraCharacteristics.LENS_FACING_BACK
- } ?: ids.firstOrNull()
- }
-
- private fun choosePreviewSize(map: StreamConfigurationMap?): android.util.Size {
- val sizes = map?.getOutputSizes(SurfaceTexture::class.java).orEmpty()
- return sizes.maxByOrNull { it.width * it.height } ?: android.util.Size(1920, 1080)
- }
-
- private fun chooseCaptureSize(map: StreamConfigurationMap?): android.util.Size {
- val sizes = map?.getOutputSizes(ImageFormat.JPEG).orEmpty()
- return sizes.maxByOrNull { it.width * it.height } ?: android.util.Size(1920, 1080)
- }
-
- private fun createOutputFile(): File {
- val publicPicturesDir =
- Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
- if (!publicPicturesDir.exists()) {
- publicPicturesDir.mkdirs()
- }
- return File(publicPicturesDir, "camera_poc_${UUID.randomUUID()}.jpg")
- }
- private fun closeCamera() {
- captureSession?.close()
- captureSession = null
- cameraDevice?.close()
- cameraDevice = null
- imageReader?.close()
- imageReader = null
- isCapturing = false
- currentOutputPath = null
- }
-
- private fun handleCameraFailure(message: String) {
- closeCamera()
- runOnUiThread {
- binding.statusText.text = message
- message.showMessage()
- setResult(RESULT_CANCELED)
- finish()
- }
- }
-
- private fun startBackgroundThread() {
- if (backgroundThread != null) return
- backgroundThread = HandlerThread("camera-preview-poc").also { it.start() }
- backgroundHandler = Handler(backgroundThread!!.looper)
- }
-
- private fun stopBackgroundThread() {
- backgroundThread?.quitSafely()
- backgroundThread?.join()
- backgroundThread = null
- backgroundHandler = null
- }
-}
diff --git a/app/src/main/java/com/nova/brain/glass/ui/SprayingActivity.kt b/app/src/main/java/com/nova/brain/glass/ui/SprayingActivity.kt
index 9d06660..45b2aee 100644
--- a/app/src/main/java/com/nova/brain/glass/ui/SprayingActivity.kt
+++ b/app/src/main/java/com/nova/brain/glass/ui/SprayingActivity.kt
@@ -1,19 +1,26 @@
package com.nova.brain.glass.ui
import android.content.Intent
+import android.os.Environment
import androidx.recyclerview.widget.RecyclerView
import com.nova.brain.glass.R
import com.nova.brain.glass.databinding.ActivitySprayingBinding
+import com.nova.brain.glass.helper.GlassMediaServiceHelper
import com.nova.brain.glass.helper.OfflineCmdListener
import com.nova.brain.glass.helper.OfflineCmdServiceHelper
import com.nova.brain.glass.helper.SprayingPhotoManager
import com.nova.brain.glass.model.ItemItem
import com.nova.brain.glass.viewmodel.SprayingVM
+import com.rokid.security.glass3.sdk.base.data.media.PhotoResolution
+import com.rokid.security.system.server.media.callback.PhotoFileCallback
import com.xuqm.base.adapter.BasePagedAdapter
import com.xuqm.base.adapter.CommonPagedAdapter
import com.xuqm.base.adapter.ViewHolder
+import com.xuqm.base.common.LogHelper
import com.xuqm.base.extensions.showMessage
import com.xuqm.base.ui.BaseListFormLayoutNormalActivity
+import java.io.File
+import java.util.UUID
class SprayingActivity :
BaseListFormLayoutNormalActivity() {
@@ -28,10 +35,6 @@ class SprayingActivity :
}
private var productionInfoId: String = ""
- companion object {
- private const val REQUEST_CAMERA_PREVIEW = 2001
- }
-
private val listener = object : OfflineCmdListener {
override fun onOfflineCmd(cmd: String) {
runOnUiThread {
@@ -45,6 +48,7 @@ class SprayingActivity :
binding.hint.text = "拍照中,请稍后..."
}
SprayingPhotoManager.clear()
+ isPhoto = true
takePhoto()
}
}
@@ -54,10 +58,46 @@ class SprayingActivity :
}
fun takePhoto() {
- startActivityForResult(
- Intent(this, CameraPreviewPocActivity::class.java),
- REQUEST_CAMERA_PREVIEW
- )
+ val fileName = "test_${System.currentTimeMillis()}.png"
+ val publicPicturesDir =
+ Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
+ val file = File(publicPicturesDir, fileName)
+ GlassMediaServiceHelper.takePhoto(PhotoResolution.RESOLUTION_1080P, file.absolutePath)
+ }
+
+ private val photoCallbackId = UUID.randomUUID().toString()
+
+ private val mPhotoFileCallback = object : PhotoFileCallback.Stub() {
+ override fun onTakePhoto(path: String) {
+ LogHelper.d("onTakePhoto-->path = $path")
+ }
+
+ override fun getCallbackId(): String {
+ return photoCallbackId
+ }
+
+ override fun onTakePhotoV2(path: String?, width: Int, height: Int) {
+ LogHelper.d("width:$width--height:$height")
+ if (path == null) {
+ if (isPhoto) {
+ isPhoto = false
+ takePhoto()
+ } else {
+ runOnUiThread {
+ binding.hint.text = "单击或语音输入“开始”,进入下一步"
+ }
+ "相机异常".showMessage()
+ }
+ } else {
+ SprayingPhotoManager.addPhoto(path)
+ startActivity(Intent(this@SprayingActivity, SprayingOCRActivity::class.java).apply {
+ putExtra("path", path)
+ putExtra("taskId", taskId)
+ putExtra("productionInfoId", productionInfoId)
+ })
+ finish()
+ }
+ }
}
@@ -83,6 +123,7 @@ class SprayingActivity :
override fun onResume() {
super.onResume()
+ GlassMediaServiceHelper.addPhotoCallback(mPhotoFileCallback)
OfflineCmdServiceHelper.addOnLineListener(listener)
OfflineCmdServiceHelper.addListenerSpraying()
}
@@ -91,28 +132,7 @@ class SprayingActivity :
super.onPause()
OfflineCmdServiceHelper.removeListenerSpraying()
OfflineCmdServiceHelper.removeOnLineListener(listener)
- }
-
- override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
- super.onActivityResult(requestCode, resultCode, data)
- if (requestCode != REQUEST_CAMERA_PREVIEW) return
- if (resultCode != RESULT_OK) {
- binding.hint.text = "单击或语音输入“开始”,进入下一步"
- return
- }
- val path = data?.getStringExtra(CameraPreviewPocActivity.EXTRA_PHOTO_PATH)
- if (path.isNullOrBlank()) {
- binding.hint.text = "单击或语音输入“开始”,进入下一步"
- "未获取到照片".showMessage()
- return
- }
- SprayingPhotoManager.addPhoto(path)
- startActivity(Intent(this, SprayingOCRActivity::class.java).apply {
- putExtra("path", path)
- putExtra("taskId", taskId)
- putExtra("productionInfoId", productionInfoId)
- })
- finish()
+ GlassMediaServiceHelper.removePhotoCallback(mPhotoFileCallback)
}
override fun onDestroy() {
@@ -120,6 +140,7 @@ class SprayingActivity :
window.clearFlags(android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
+ private var isPhoto = false
private val adapter = object : CommonPagedAdapter(R.layout.item_photo) {
override fun convert(holder: ViewHolder, item: ItemItem, position: Int) {
holder
@@ -130,6 +151,7 @@ class SprayingActivity :
binding.hint.text = "拍照中,请稍后..."
}
SprayingPhotoManager.clear()
+ isPhoto = true
takePhoto()
}
}
diff --git a/app/src/main/res/layout/activity_camera_preview_poc.xml b/app/src/main/res/layout/activity_camera_preview_poc.xml
deleted file mode 100644
index 108e875..0000000
--- a/app/src/main/res/layout/activity_camera_preview_poc.xml
+++ /dev/null
@@ -1,104 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-