feat(camera): 添加相机预览功能并集成语音控制
- 在 OfflineCmdServiceHelper 中新增拍照、拍摄、缩放等语音命令 - 移除 SprayingActivity 中旧的相机拍照实现,改为启动 CameraPreviewPocActivity - 添加 CameraPreviewPocActivity 实现完整的相机预览、拍照和缩放功能 - 集成语音命令控制相机操作,支持拍照、放大、缩小、取消等功能 - 添加相机预览界面布局文件和相关资源 - 优化相机权限处理和错误状态反馈
这个提交包含在:
父节点
b00a70f7ec
当前提交
8258d77f1f
@ -90,6 +90,9 @@
|
||||
<activity
|
||||
android:name=".ui.InspectionCompleteActivity"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".ui.CameraPreviewPocActivity"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".ui.SprayingActivity"
|
||||
android:exported="false" />
|
||||
|
||||
@ -45,7 +45,14 @@ object OfflineCmdServiceHelper {
|
||||
)
|
||||
private val CMDS_SPRAYING = listOf(
|
||||
OfflineCmdBean("开始", "kai shi"),
|
||||
OfflineCmdBean("开始任务", "kai shi ren wu")
|
||||
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")
|
||||
)
|
||||
private val CMDS_SPRAYING_FINISH = listOf(
|
||||
OfflineCmdBean("补充照片", "bu chong zhao pian"),
|
||||
|
||||
@ -0,0 +1,407 @@
|
||||
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<ActivityCameraPreviewPocBinding>() {
|
||||
|
||||
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<out String>,
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -1,26 +1,19 @@
|
||||
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<ItemItem, SprayingVM, ActivitySprayingBinding>() {
|
||||
@ -35,6 +28,10 @@ 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 {
|
||||
@ -48,7 +45,6 @@ class SprayingActivity :
|
||||
binding.hint.text = "拍照中,请稍后..."
|
||||
}
|
||||
SprayingPhotoManager.clear()
|
||||
isPhoto = true
|
||||
takePhoto()
|
||||
}
|
||||
}
|
||||
@ -58,50 +54,10 @@ class SprayingActivity :
|
||||
}
|
||||
|
||||
fun takePhoto() {
|
||||
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()
|
||||
// runOnUiThread {
|
||||
// binding.hint.text = "单击或语音输入“开始”,进入下一步"
|
||||
// binding.iv.setImageBitmap(BitmapFactory.decodeFile(path))
|
||||
// }
|
||||
}
|
||||
}
|
||||
startActivityForResult(
|
||||
Intent(this, CameraPreviewPocActivity::class.java),
|
||||
REQUEST_CAMERA_PREVIEW
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -127,7 +83,6 @@ class SprayingActivity :
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
GlassMediaServiceHelper.addPhotoCallback(mPhotoFileCallback)
|
||||
OfflineCmdServiceHelper.addOnLineListener(listener)
|
||||
OfflineCmdServiceHelper.addListenerSpraying()
|
||||
}
|
||||
@ -136,7 +91,28 @@ class SprayingActivity :
|
||||
super.onPause()
|
||||
OfflineCmdServiceHelper.removeListenerSpraying()
|
||||
OfflineCmdServiceHelper.removeOnLineListener(listener)
|
||||
GlassMediaServiceHelper.removePhotoCallback(mPhotoFileCallback)
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
@ -144,7 +120,6 @@ class SprayingActivity :
|
||||
window.clearFlags(android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
}
|
||||
|
||||
private var isPhoto = false
|
||||
private val adapter = object : CommonPagedAdapter<ItemItem>(R.layout.item_photo) {
|
||||
override fun convert(holder: ViewHolder, item: ItemItem, position: Int) {
|
||||
holder
|
||||
@ -155,7 +130,6 @@ class SprayingActivity :
|
||||
binding.hint.text = "拍照中,请稍后..."
|
||||
}
|
||||
SprayingPhotoManager.clear()
|
||||
isPhoto = true
|
||||
takePhoto()
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,104 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@android:color/black">
|
||||
|
||||
<TextureView
|
||||
android:id="@+id/previewView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:keepScreenOn="true"
|
||||
app:layout_constraintBottom_toTopOf="@+id/controlBar"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/statusText"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:background="@drawable/bg_item"
|
||||
android:gravity="center"
|
||||
android:paddingHorizontal="12dp"
|
||||
android:paddingVertical="6dp"
|
||||
android:text="相机预览验证中"
|
||||
android:textColor="#FF40FF5E"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/zoomText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:background="@drawable/bg_item"
|
||||
android:paddingHorizontal="12dp"
|
||||
android:paddingVertical="6dp"
|
||||
android:text="缩放 1.0x"
|
||||
android:textColor="#FF40FF5E"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/statusText" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/controlBar"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:background="@drawable/bg_task_title_selected"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
android:padding="10dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/zoomOutButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/bg_photo"
|
||||
android:gravity="center"
|
||||
android:paddingVertical="8dp"
|
||||
android:text="拉远"
|
||||
android:textColor="#FF40FF5E"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/captureButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="12dp"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/bg_photo"
|
||||
android:gravity="center"
|
||||
android:paddingVertical="8dp"
|
||||
android:text="拍照"
|
||||
android:textColor="#FF40FF5E"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/zoomInButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/bg_photo"
|
||||
android:gravity="center"
|
||||
android:paddingVertical="8dp"
|
||||
android:text="拉近"
|
||||
android:textColor="#FF40FF5E"
|
||||
android:textSize="16sp" />
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</layout>
|
||||
正在加载...
在新工单中引用
屏蔽一个用户