diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index bcb8d41..463100c 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -26,6 +26,10 @@
+
\ No newline at end of file
diff --git a/app/src/main/java/com/example/app/CameraActivity.kt b/app/src/main/java/com/example/app/CameraActivity.kt
index a2f21d7..348b9f6 100644
--- a/app/src/main/java/com/example/app/CameraActivity.kt
+++ b/app/src/main/java/com/example/app/CameraActivity.kt
@@ -49,6 +49,7 @@ class CameraActivity : AppCompatActivity() {
private lateinit var photoPreviewLayout: LinearLayout
private var imageCapture: ImageCapture? = null
private lateinit var cameraExecutor: ExecutorService
+ private var cameraProvider: ProcessCameraProvider? = null
// 存储拍摄的图片URI
private val capturedImageUris = mutableListOf()
@@ -65,6 +66,9 @@ class CameraActivity : AppCompatActivity() {
settingsButton = findViewById(R.id.settingsButton)
photoPreviewLayout = findViewById(R.id.photoPreviewLayout)
+ // 初始化线程池
+ cameraExecutor = Executors.newSingleThreadExecutor()
+
// 请求权限
if (allPermissionsGranted()) {
startCamera()
@@ -77,9 +81,12 @@ class CameraActivity : AppCompatActivity() {
// 设置点击监听器
captureButton.setOnClickListener { takePhoto() }
settingsButton.setOnClickListener { openSettings() }
+ }
- // 初始化线程池
- cameraExecutor = Executors.newSingleThreadExecutor()
+ override fun onDestroy() {
+ super.onDestroy()
+ cameraExecutor.shutdown()
+ cameraProvider?.unbindAll()
}
private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
@@ -90,35 +97,39 @@ class CameraActivity : AppCompatActivity() {
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener({
- val cameraProvider = cameraProviderFuture.get()
-
- // 预览
- val preview = Preview.Builder()
- .build()
- .also {
- it.setSurfaceProvider(viewFinder.surfaceProvider)
- }
-
- imageCapture = ImageCapture.Builder()
- .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
- .build()
-
- val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
-
try {
- cameraProvider.unbindAll()
- cameraProvider.bindToLifecycle(
+ cameraProvider = cameraProviderFuture.get()
+
+ // 预览
+ val preview = Preview.Builder()
+ .build()
+ .also {
+ it.setSurfaceProvider(viewFinder.surfaceProvider)
+ }
+
+ imageCapture = ImageCapture.Builder()
+ .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
+ .build()
+
+ val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
+
+ cameraProvider?.unbindAll()
+ cameraProvider?.bindToLifecycle(
this, cameraSelector, preview, imageCapture
)
} catch (e: Exception) {
- Log.e(TAG, "相机绑定失败", e)
+ Log.e(TAG, "相机初始化失败: ${e.message}", e)
+ Toast.makeText(this, "相机启动失败: ${e.message}", Toast.LENGTH_LONG).show()
}
}, ContextCompat.getMainExecutor(this))
}
@SuppressLint("MissingPermission")
private fun takePhoto() {
- val imageCapture = this.imageCapture ?: return
+ val imageCapture = this.imageCapture ?: run {
+ Toast.makeText(this, "相机未准备好", Toast.LENGTH_SHORT).show()
+ return
+ }
val outputOptions = createOutputFileOptions()
@@ -143,7 +154,7 @@ class CameraActivity : AppCompatActivity() {
override fun onError(exception: ImageCaptureException) {
Log.e(TAG, "拍照失败: ${exception.message}", exception)
- Toast.makeText(baseContext, "拍照失败", Toast.LENGTH_SHORT).show()
+ Toast.makeText(baseContext, "拍照失败: ${exception.message}", Toast.LENGTH_LONG).show()
}
}
)
@@ -308,8 +319,9 @@ class CameraActivity : AppCompatActivity() {
if (allPermissionsGranted()) {
startCamera()
} else {
- Toast.makeText(this, "权限被拒绝,相机功能不可用", Toast.LENGTH_SHORT).show()
- // 可以在这里提供降级功能,比如手动输入位置信息
+ Toast.makeText(this, "相机权限被拒绝,应用无法使用相机功能", Toast.LENGTH_LONG).show()
+ // 可以选择关闭应用或提供替代功能
+ finish()
}
}
}
diff --git a/app/src/main/java/com/example/app/MainActivity.kt b/app/src/main/java/com/example/app/MainActivity.kt
index c81cc19..943a394 100644
--- a/app/src/main/java/com/example/app/MainActivity.kt
+++ b/app/src/main/java/com/example/app/MainActivity.kt
@@ -9,8 +9,8 @@ class MainActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
- // 直接启动相机Activity
- startActivity(Intent(this, CameraActivity::class.java))
+ // 启动极简相机Activity
+ startActivity(Intent(this, SimpleCameraActivity::class.java))
finish() // 关闭MainActivity,避免返回键回到空白页面
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/app/SimpleCameraActivity.kt b/app/src/main/java/com/example/app/SimpleCameraActivity.kt
new file mode 100644
index 0000000..d151723
--- /dev/null
+++ b/app/src/main/java/com/example/app/SimpleCameraActivity.kt
@@ -0,0 +1,170 @@
+package com.example.app
+
+import android.Manifest
+import android.content.ContentValues
+import android.content.pm.PackageManager
+import android.os.Build
+import android.os.Bundle
+import android.provider.MediaStore
+import android.util.Log
+import android.widget.Toast
+import androidx.appcompat.app.AppCompatActivity
+import androidx.camera.core.CameraSelector
+import androidx.camera.core.ImageCapture
+import androidx.camera.core.ImageCaptureException
+import androidx.camera.core.Preview
+import androidx.camera.lifecycle.ProcessCameraProvider
+import androidx.camera.view.PreviewView
+import androidx.core.app.ActivityCompat
+import androidx.core.content.ContextCompat
+import com.google.android.material.floatingactionbutton.FloatingActionButton
+import java.text.SimpleDateFormat
+import java.util.*
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
+
+class SimpleCameraActivity : AppCompatActivity() {
+
+ companion object {
+ private const val TAG = "SimpleCamera"
+ private const val REQUEST_CODE_PERMISSIONS = 10
+ private val REQUIRED_PERMISSIONS = arrayOf(
+ Manifest.permission.CAMERA
+ )
+ }
+
+ private lateinit var viewFinder: PreviewView
+ private lateinit var captureButton: FloatingActionButton
+ private var imageCapture: ImageCapture? = null
+ private lateinit var cameraExecutor: ExecutorService
+ private var cameraProvider: ProcessCameraProvider? = null
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_simple_camera)
+
+ // 初始化视图
+ viewFinder = findViewById(R.id.viewFinder)
+ captureButton = findViewById(R.id.captureButton)
+
+ // 初始化线程池
+ cameraExecutor = Executors.newSingleThreadExecutor()
+
+ // 请求权限
+ if (allPermissionsGranted()) {
+ startCamera()
+ } else {
+ ActivityCompat.requestPermissions(
+ this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS
+ )
+ }
+
+ // 设置拍照按钮点击监听器
+ captureButton.setOnClickListener { takePhoto() }
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ cameraExecutor.shutdown()
+ cameraProvider?.unbindAll()
+ }
+
+ private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
+ ContextCompat.checkSelfPermission(baseContext, it) == PackageManager.PERMISSION_GRANTED
+ }
+
+ private fun startCamera() {
+ val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
+
+ cameraProviderFuture.addListener({
+ try {
+ cameraProvider = cameraProviderFuture.get()
+
+ // 预览
+ val preview = Preview.Builder()
+ .build()
+ .also {
+ it.setSurfaceProvider(viewFinder.surfaceProvider)
+ }
+
+ imageCapture = ImageCapture.Builder()
+ .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
+ .build()
+
+ val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
+
+ cameraProvider?.unbindAll()
+ cameraProvider?.bindToLifecycle(
+ this, cameraSelector, preview, imageCapture
+ )
+
+ Log.d(TAG, "相机启动成功")
+ } catch (e: Exception) {
+ Log.e(TAG, "相机初始化失败: ${e.message}", e)
+ Toast.makeText(this, "相机启动失败: ${e.message}", Toast.LENGTH_LONG).show()
+ finish()
+ }
+ }, ContextCompat.getMainExecutor(this))
+ }
+
+ private fun takePhoto() {
+ val imageCapture = this.imageCapture ?: run {
+ Toast.makeText(this, "相机未准备好", Toast.LENGTH_SHORT).show()
+ return
+ }
+
+ val timestamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
+
+ val contentValues = ContentValues().apply {
+ put(MediaStore.MediaColumns.DISPLAY_NAME, "巡检_$timestamp")
+ put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ put(MediaStore.MediaColumns.RELATIVE_PATH, "Pictures/LogCam")
+ }
+ }
+
+ val contentResolver = contentResolver
+ val uri = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
+
+ if (uri == null) {
+ Toast.makeText(this, "创建文件失败", Toast.LENGTH_SHORT).show()
+ return
+ }
+
+ val outputOptions = ImageCapture.OutputFileOptions.Builder(contentResolver, uri, contentValues).build()
+
+ imageCapture.takePicture(
+ outputOptions,
+ ContextCompat.getMainExecutor(this),
+ object : ImageCapture.OnImageSavedCallback {
+ override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
+ val savedUri = outputFileResults.savedUri ?: return
+ val msg = "照片已保存: ${savedUri.lastPathSegment}"
+ Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
+ Log.d(TAG, msg)
+ }
+
+ override fun onError(exception: ImageCaptureException) {
+ Log.e(TAG, "拍照失败: ${exception.message}", exception)
+ Toast.makeText(baseContext, "拍照失败: ${exception.message}", Toast.LENGTH_LONG).show()
+ }
+ }
+ )
+ }
+
+ override fun onRequestPermissionsResult(
+ requestCode: Int,
+ permissions: Array,
+ grantResults: IntArray
+ ) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+ if (requestCode == REQUEST_CODE_PERMISSIONS) {
+ if (allPermissionsGranted()) {
+ startCamera()
+ } else {
+ Toast.makeText(this, "相机权限被拒绝,应用无法使用相机功能", Toast.LENGTH_LONG).show()
+ finish()
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_simple_camera.xml b/app/src/main/res/layout/activity_simple_camera.xml
new file mode 100644
index 0000000..0c04083
--- /dev/null
+++ b/app/src/main/res/layout/activity_simple_camera.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index f8c6127..e88c0b3 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -7,4 +7,5 @@
#FF018786
#FF000000
#FFFFFFFF
+ #FF6200EE
\ No newline at end of file
diff --git a/create-signing.sh b/create-signing.sh
new file mode 100644
index 0000000..0bf51fc
--- /dev/null
+++ b/create-signing.sh
@@ -0,0 +1,83 @@
+#!/bin/bash
+# 创建Android应用签名文件并生成Base64字符串
+
+echo "=== Android应用签名生成工具 ==="
+echo ""
+
+# 检查keytool是否可用
+if ! command -v keytool &> /dev/null; then
+ echo "❌ keytool命令未找到,请安装Java JDK"
+ exit 1
+fi
+
+# 签名配置
+KEYSTORE_NAME="logcam-release.jks"
+ALIAS="logcam-release-key"
+STORE_PASS="android123"
+KEY_PASS="android123"
+DNAME="CN=LogCam, OU=Development, O=Example, L=Beijing, ST=Beijing, C=CN"
+
+echo "📋 签名配置:"
+echo " - 密钥库文件: $KEYSTORE_NAME"
+echo " - 别名: $ALIAS"
+echo " - 密钥库密码: $STORE_PASS"
+echo " - 密钥密码: $KEY_PASS"
+echo ""
+
+# 生成签名文件
+echo "🔑 生成签名文件..."
+keytool -genkeypair -v \
+ -keystore "$KEYSTORE_NAME" \
+ -keyalg RSA -keysize 2048 \
+ -validity 10000 \
+ -alias "$ALIAS" \
+ -storepass "$STORE_PASS" \
+ -keypass "$KEY_PASS" \
+ -dname "$DNAME"
+
+if [ $? -eq 0 ]; then
+ echo "✅ 签名文件生成成功: $KEYSTORE_NAME"
+ ls -la "$KEYSTORE_NAME"
+else
+ echo "❌ 签名文件生成失败"
+ exit 1
+fi
+
+echo ""
+echo "🔄 生成Base64字符串..."
+# 生成Base64字符串
+SIGNING_KEY_BASE64=$(base64 -w 0 "$KEYSTORE_NAME")
+if [ $? -eq 0 ]; then
+ echo "✅ Base64字符串生成成功"
+else
+ echo "❌ Base64转换失败"
+ exit 1
+fi
+
+echo ""
+echo "📋 GitHub Secrets配置信息:"
+echo "========================================"
+echo "SIGNING_KEY (密钥文件Base64):"
+echo "$SIGNING_KEY_BASE64"
+echo "========================================"
+echo ""
+echo "ALIAS (别名): $ALIAS"
+echo "KEYSTORE_PASSWORD (密钥库密码): $STORE_PASS"
+echo "KEY_PASSWORD (密钥密码): $KEY_PASS"
+echo "========================================"
+echo ""
+echo "📱 后续步骤:"
+echo "1. 访问 https://github.com/xiajid/logcam/settings/secrets/actions"
+echo "2. 创建以下Secrets:"
+echo " - SIGNING_KEY: 粘贴上面的Base64字符串"
+echo " - ALIAS: \"$ALIAS\""
+echo " - KEYSTORE_PASSWORD: \"$STORE_PASS\""
+echo " - KEY_PASSWORD: \"$KEY_PASS\""
+echo "3. 提交新工作流文件"
+echo "4. 触发构建获得签名版APK"
+echo ""
+echo "🔧 签名文件信息:"
+keytool -list -v -keystore "$KEYSTORE_NAME" -storepass "$STORE_PASS" | grep -E "别名|有效期|指纹"
+
+echo ""
+echo "✅ 签名流程完成"
\ No newline at end of file