diff --git a/app/build.gradle b/app/build.gradle
index ba53863..603b8d5 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -84,7 +84,7 @@ dependencies {
implementation 'com.google.android.material:material:1.3.0'
implementation "io.noties.markwon:core:4.6.2"
- implementation ('com.rokid.security:glass3.open.sdk:2.1.6-E') {
+ implementation ('com.rokid.security:glass3.open.sdk:2.1.7-E') {
exclude group: "org.slf4j"
}
implementation 'com.rokid.security.sdk:online-speech:0.1.0'
diff --git a/app/src/main/java/com/nova/brain/glass/helper/GlassMediaServiceHelper.kt b/app/src/main/java/com/nova/brain/glass/helper/GlassMediaServiceHelper.kt
index 9d89f1c..8a62b2e 100644
--- a/app/src/main/java/com/nova/brain/glass/helper/GlassMediaServiceHelper.kt
+++ b/app/src/main/java/com/nova/brain/glass/helper/GlassMediaServiceHelper.kt
@@ -1,6 +1,8 @@
package com.nova.brain.glass.helper
+import android.view.Surface
import com.rokid.security.glass3.open.sdk.GlassSdk
+import com.rokid.security.system.server.media.callback.ICameraSurfaceCallback
import com.rokid.security.system.server.media.callback.PhotoFileCallback
object GlassMediaServiceHelper {
@@ -34,4 +36,35 @@ object GlassMediaServiceHelper {
service.javaClass.getMethod("removePhotoCallback", PhotoFileCallback::class.java)
.invoke(service, callback)
}
+
+ fun startCameraShare(surface: Surface, callback: ICameraSurfaceCallback) {
+ val service = service() ?: return
+ service.javaClass.getMethod(
+ "startCameraShare",
+ Surface::class.java,
+ ICameraSurfaceCallback::class.java
+ ).invoke(service, surface, callback)
+ }
+
+ fun stopCameraShare(callback: ICameraSurfaceCallback) {
+ val service = service() ?: return
+ service.javaClass.getMethod("stopCameraShare", ICameraSurfaceCallback::class.java)
+ .invoke(service, callback)
+ }
+
+ fun getMaxZoomLevel(): Int {
+ val service = service() ?: return 0
+ return (service.javaClass.getMethod("getMaxZoomLevel").invoke(service) as? Int) ?: 0
+ }
+
+ fun getZoomLevel(): Int {
+ val service = service() ?: return 0
+ return (service.javaClass.getMethod("getZoomLevel").invoke(service) as? Int) ?: 0
+ }
+
+ fun zoomCamera(level: Int) {
+ val service = service() ?: return
+ service.javaClass.getMethod("zoomCamera", Int::class.javaPrimitiveType)
+ .invoke(service, level)
+ }
}
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 f34a6fb..ed0b2fa 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
@@ -43,6 +43,16 @@ object OfflineCmdServiceHelper {
OfflineCmdBean("通过", "tong guo"),
OfflineCmdBean("同意", "tong yi")
)
+ private val CMDS_INSPECTION_CAPTURE = 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")
+ )
private val CMDS_SPRAYING = listOf(
OfflineCmdBean("开始", "kai shi"),
OfflineCmdBean("开始任务", "kai shi ren wu")
@@ -158,6 +168,8 @@ object OfflineCmdServiceHelper {
fun addListenerInspection() = registerBeans(CMDS_INSPECTION)
+ fun addListenerInspectionCapture() = registerBeans(CMDS_INSPECTION_CAPTURE)
+
fun addListenerSpraying() = registerBeans(CMDS_SPRAYING)
fun addListenerSprayingFinish() = registerBeans(CMDS_SPRAYING_FINISH)
@@ -176,6 +188,8 @@ object OfflineCmdServiceHelper {
fun removeListenerInspection() = removeBeans(CMDS_INSPECTION)
+ fun removeListenerInspectionCapture() = removeBeans(CMDS_INSPECTION_CAPTURE)
+
fun removeListenerSpraying() = removeBeans(CMDS_SPRAYING)
fun removeListenerSprayingFinish() = removeBeans(CMDS_SPRAYING_FINISH)
diff --git a/app/src/main/java/com/nova/brain/glass/ui/InspectionActivity.kt b/app/src/main/java/com/nova/brain/glass/ui/InspectionActivity.kt
index b0d8583..e5140b4 100644
--- a/app/src/main/java/com/nova/brain/glass/ui/InspectionActivity.kt
+++ b/app/src/main/java/com/nova/brain/glass/ui/InspectionActivity.kt
@@ -3,6 +3,9 @@ package com.nova.brain.glass.ui
import android.content.Intent
import android.os.Environment
import android.view.WindowManager
+import android.view.Surface
+import android.view.TextureView
+import android.view.View
import androidx.recyclerview.widget.RecyclerView
import com.nova.brain.glass.R
import com.nova.brain.glass.databinding.ActivityInspectionBinding
@@ -14,6 +17,7 @@ import com.nova.brain.glass.model.ItemItem
import com.nova.brain.glass.viewmodel.InspectionValidateState
import com.nova.brain.glass.viewmodel.InspectionVM
import com.rokid.security.glass3.sdk.base.data.media.PhotoResolution
+import com.rokid.security.system.server.media.callback.ICameraSurfaceCallback
import com.rokid.security.system.server.media.callback.PhotoFileCallback
import com.xuqm.base.adapter.BasePagedAdapter
import com.xuqm.base.adapter.CommonPagedAdapter
@@ -33,22 +37,88 @@ class InspectionActivity :
private val glassTaskId: String by lazy { intent.getStringExtra("glassTaskId").orEmpty() }
private var pendingPhotoPath: String? = null
+ private var isPreviewRequested = false
+ private var isPreviewActive = false
+ private var currentZoomLevel = 1
+ private var maxZoomLevel = 1
private val listener = object : OfflineCmdListener {
override fun onOfflineCmd(cmd: String) {
runOnUiThread {
when (cmd) {
"退出", "返回", "退回" -> finish()
- "开始", "开始任务", "拍照" -> startCapture()
+ "开始", "开始任务" -> startCapture()
+ "拍照", "拍摄" -> if (isPreviewActive) capturePhoto() else startCapture()
+ "放大", "拉近" -> adjustZoom(1)
+ "缩小", "拉远" -> adjustZoom(-1)
}
}
}
}
+ private val cameraSurfaceCallbackId = UUID.randomUUID().toString()
+ private val cameraSurfaceCallback = object : ICameraSurfaceCallback.Stub() {
+ override fun onCameraOpened(width: Int, height: Int) {
+ isPreviewActive = true
+ currentZoomLevel = GlassMediaServiceHelper.getZoomLevel().coerceAtLeast(1)
+ maxZoomLevel = GlassMediaServiceHelper.getMaxZoomLevel().coerceAtLeast(1)
+ runOnUiThread {
+ binding.cameraPreview.visibility = View.VISIBLE
+ binding.zoomText.visibility = View.VISIBLE
+ updateZoomText()
+ binding.hint.text = "预览中,单击预览或语音输入“拍照”完成拍摄"
+ }
+ }
+
+ override fun onCameraClosed() {
+ isPreviewActive = false
+ runOnUiThread {
+ binding.cameraPreview.visibility = View.GONE
+ binding.zoomText.visibility = View.GONE
+ }
+ }
+
+ override fun onError(code: Int, message: String?) {
+ isPreviewActive = false
+ runOnUiThread {
+ binding.cameraPreview.visibility = View.GONE
+ binding.zoomText.visibility = View.GONE
+ binding.hint.text = "相机预览失败,请重试"
+ (message ?: "相机预览失败").showMessage()
+ }
+ }
+
+ override fun getCallbackId(): String = cameraSurfaceCallbackId
+ }
+
+ private val previewTextureListener = object : TextureView.SurfaceTextureListener {
+ override fun onSurfaceTextureAvailable(surface: android.graphics.SurfaceTexture, width: Int, height: Int) {
+ if (isPreviewRequested) {
+ startCameraPreview()
+ }
+ }
+
+ override fun onSurfaceTextureSizeChanged(
+ surface: android.graphics.SurfaceTexture,
+ width: Int,
+ height: Int
+ ) = Unit
+
+ override fun onSurfaceTextureDestroyed(surface: android.graphics.SurfaceTexture): Boolean = true
+
+ override fun onSurfaceTextureUpdated(surface: android.graphics.SurfaceTexture) = Unit
+ }
+
override fun initData() {
super.initData()
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
SprayingPhotoManager.clear()
+ binding.cameraPreview.surfaceTextureListener = previewTextureListener
+ binding.cameraPreview.setOnClickListener {
+ if (isPreviewActive) {
+ capturePhoto()
+ }
+ }
viewModel.taskInfo.observe(this) { item ->
if (item != null) {
@@ -95,11 +165,68 @@ class InspectionActivity :
private fun startCapture() {
if (viewModel.validateState.value == InspectionValidateState.LOADING) return
- binding.hint.text = "拍照中,请稍后..."
+ if (isPreviewActive) {
+ capturePhoto()
+ return
+ }
+ binding.hint.text = "相机预览启动中,请稍后..."
+ isPreviewRequested = true
SprayingPhotoManager.clear()
+ if (binding.cameraPreview.isAvailable) {
+ startCameraPreview()
+ } else {
+ binding.cameraPreview.visibility = View.VISIBLE
+ binding.zoomText.visibility = View.VISIBLE
+ }
+ }
+
+ private fun startCameraPreview() {
+ val surfaceTexture = binding.cameraPreview.surfaceTexture ?: return
+ val surface = Surface(surfaceTexture)
+ runCatching {
+ GlassMediaServiceHelper.startCameraShare(surface, cameraSurfaceCallback)
+ }.onFailure {
+ isPreviewRequested = false
+ binding.cameraPreview.visibility = View.GONE
+ binding.zoomText.visibility = View.GONE
+ binding.hint.text = "相机预览启动失败,请重试"
+ (it.message ?: "相机预览启动失败").showMessage()
+ }
+ }
+
+ private fun stopCameraPreview() {
+ isPreviewRequested = false
+ isPreviewActive = false
+ runCatching {
+ GlassMediaServiceHelper.stopCameraShare(cameraSurfaceCallback)
+ }
+ binding.cameraPreview.visibility = View.GONE
+ binding.zoomText.visibility = View.GONE
+ }
+
+ private fun capturePhoto() {
+ if (viewModel.validateState.value == InspectionValidateState.LOADING) return
+ binding.hint.text = "拍照中,请稍后..."
takePhoto()
}
+ private fun adjustZoom(delta: Int) {
+ if (!isPreviewActive) return
+ maxZoomLevel = GlassMediaServiceHelper.getMaxZoomLevel().coerceAtLeast(1)
+ currentZoomLevel = (GlassMediaServiceHelper.getZoomLevel() + delta).coerceIn(1, maxZoomLevel)
+ runCatching {
+ GlassMediaServiceHelper.zoomCamera(currentZoomLevel)
+ }.onSuccess {
+ updateZoomText()
+ }.onFailure {
+ (it.message ?: "缩放失败").showMessage()
+ }
+ }
+
+ private fun updateZoomText() {
+ binding.zoomText.text = "缩放 ${currentZoomLevel}x"
+ }
+
private fun takePhoto() {
val fileName = "inspection_${System.currentTimeMillis()}.png"
val file = File(
@@ -121,6 +248,7 @@ class InspectionActivity :
override fun onTakePhotoV2(path: String?, width: Int, height: Int) {
if (path == null) {
runOnUiThread {
+ stopCameraPreview()
binding.hint.text = "单击或语音输入\"开始\",进入下一步"
}
"相机异常".showMessage()
@@ -129,6 +257,7 @@ class InspectionActivity :
SprayingPhotoManager.addPhoto(path)
pendingPhotoPath = path
runOnUiThread {
+ stopCameraPreview()
viewModel.validateDocument(path)
}
}
@@ -152,12 +281,15 @@ class InspectionActivity :
super.onResume()
GlassMediaServiceHelper.addPhotoCallback(mPhotoFileCallback)
OfflineCmdServiceHelper.addOnLineListener(listener)
+ OfflineCmdServiceHelper.addListenerInspectionCapture()
}
override fun onPause() {
super.onPause()
+ stopCameraPreview()
GlassMediaServiceHelper.removePhotoCallback(mPhotoFileCallback)
OfflineCmdServiceHelper.removeOnLineListener(listener)
+ OfflineCmdServiceHelper.removeListenerInspectionCapture()
}
override fun onDestroy() {
diff --git a/app/src/main/res/layout/activity_inspection.xml b/app/src/main/res/layout/activity_inspection.xml
index f308e70..4ce5da0 100644
--- a/app/src/main/res/layout/activity_inspection.xml
+++ b/app/src/main/res/layout/activity_inspection.xml
@@ -104,5 +104,37 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/baseRecyclerView" />
+
+
+
+
-
\ No newline at end of file
+