diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
new file mode 100644
index 0000000..7643783
--- /dev/null
+++ b/.idea/codeStyles/Project.xml
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ xmlns:android
+
+ ^$
+
+
+
+
+
+
+
+
+ xmlns:.*
+
+ ^$
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*:id
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ .*:name
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ name
+
+ ^$
+
+
+
+
+
+
+
+
+ style
+
+ ^$
+
+
+
+
+
+
+
+
+ .*
+
+ ^$
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*
+
+ http://schemas.android.com/apk/res/android
+
+
+ ANDROID_ATTRIBUTE_ORDER
+
+
+
+
+
+
+ .*
+
+ .*
+
+
+ BY_NAME
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
new file mode 100644
index 0000000..79ee123
--- /dev/null
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 0ad17cb..8978d23 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,4 +1,3 @@
-
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 5f0fff5..ad4994d 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -50,4 +50,5 @@ dependencies {
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
+ implementation ("com.squareup.okhttp3:okhttp:4.12.0")
}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 343a860..99a9930 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -9,6 +9,10 @@
+
+
+
+
diff --git a/app/src/main/java/com/bing89/travebing/MainActivity.kt b/app/src/main/java/com/bing89/travebing/MainActivity.kt
index c5e67fa..e5a9e31 100644
--- a/app/src/main/java/com/bing89/travebing/MainActivity.kt
+++ b/app/src/main/java/com/bing89/travebing/MainActivity.kt
@@ -2,25 +2,21 @@
package com.bing89.travebing
-import android.Manifest
-import android.Manifest.*
+import android.Manifest.permission
import android.annotation.SuppressLint
import android.content.ContentValues
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
-import android.location.Criteria
import android.location.Location
import android.location.LocationListener
import android.location.LocationManager
-import android.os.Build
+import android.net.Uri
import android.os.Bundle
-import android.os.Handler
-import android.os.Looper
import android.provider.MediaStore
-import android.util.Base64
import android.util.Log
import android.widget.Button
+import android.widget.EditText
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
@@ -32,14 +28,28 @@ import androidx.camera.core.ImageCaptureException
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
-import androidx.core.content.FileProvider
-import com.bing89.travebing.R.*
-import kotlinx.coroutines.*
-import java.io.ByteArrayOutputStream
+import com.bing89.travebing.R.id
+import com.bing89.travebing.R.layout
+import kotlinx.coroutines.DelicateCoroutinesApi
+import okhttp3.Call
+import okhttp3.Callback
+import okhttp3.MediaType.Companion.toMediaType
+import okhttp3.MultipartBody
+import okhttp3.OkHttpClient
+import okhttp3.Request
+import okhttp3.RequestBody.Companion.asRequestBody
+import okhttp3.Response
+import java.io.BufferedInputStream
+import java.io.BufferedOutputStream
import java.io.File
+import java.io.FileInputStream
+import java.io.FileOutputStream
+import java.io.IOException
+import java.io.InputStream
import java.text.SimpleDateFormat
-import java.util.Date
import java.util.Locale
+import java.util.Timer
+import java.util.TimerTask
class MainActivity : AppCompatActivity() {
@@ -48,23 +58,33 @@ class MainActivity : AppCompatActivity() {
private lateinit var previewImageView: ImageView
private lateinit var gpsInfoTextView: TextView
private var imageCapture: ImageCapture? = null
-
+ private lateinit var planText: EditText
private var isMonitoring = false
private var photoFilePath: String? = null
private var locationManager: LocationManager? = null
-
+ private lateinit var lat: String
+ private lateinit var lon: String
+ private lateinit var currentImg:String
+ private lateinit var context:Context
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- setContentView(layout.activity_main)
+ lat = ""
+ lon = ""
+ currentImg = ""
+ context = baseContext
+ setContentView(layout.activity_main)
startButton = findViewById(id.startButton)
previewImageView = findViewById(id.previewImageView)
gpsInfoTextView = findViewById(id.gpsInfoTextView)
+ planText = findViewById(id.planText)
startCamera()
startButton.setOnClickListener {
if (isMonitoring) {
stopMonitoring()
+ planText.isActivated = true
} else {
+ planText.isActivated = false
startMonitoring()
}
}
@@ -73,47 +93,94 @@ class MainActivity : AppCompatActivity() {
locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
}
+ private fun updateWayCallback(file: File):Callback{
+ return object:Callback{
+ override fun onFailure(call: Call, e: IOException) {
+ file.delete()
+ println("Fail")
+ }
+
+ override fun onResponse(call: Call, response: Response) {
+ println(response.body.toString())
+ file.delete()
+ }
+
+ }
+ }
+ private fun updateWay(img:InputStream){
+ Log.d(TAG, "$img.jpg")
+ val client = OkHttpClient()
+
+ var builder: MultipartBody.Builder = MultipartBody.Builder()
+ .setType(MultipartBody.FORM)
+ .addFormDataPart("lat", lat)
+ .addFormDataPart("lon", lon)
+ val dst = File("${context.externalCacheDir}/tmp")
+ copyfile(img, dst )
+ val requestFile = dst.asRequestBody(MEDIA_TYPE_FILE)
+ builder = builder.addFormDataPart("file", "1.jpg", requestFile)
+ val multipartBody: MultipartBody = builder.build()
+ val request = Request.Builder()
+ .url("http://192.168.0.200:3000/api/v1/plans/" + planText.text + "/ways")
+ .post(multipartBody)
+ .build()
+
+ val call: Call = client.newCall(request)
+ call.enqueue(updateWayCallback(dst))
+ }
private fun startMonitoring() {
isMonitoring = true
startButton.text = "休息"
-// if(imageCapture == null ){
-// startCamera()
-// }
- takePhoto()
+ val timer = Timer()
+ val task = object : TimerTask() {
+ override fun run() {
+ // 每隔 1 秒钟执行一次此方法
+ // 在这里写下你需要执行的代码
+ takePhoto()
+ }
+ }
-// val intervalMillis = 60000L // 间隔时间,这里设置为1分钟
-// val handler = Handler(Looper.getMainLooper())
-//
-// handler.post(object : Runnable {
-// override fun run() {
-// if (isMonitoring) {
-// getLocation()
-//// capturePhotoAndUpload()
-// takePhoto()
-// handler.postDelayed(this, intervalMillis)
-// }
-// }
-// })
+ timer.schedule(task, 0, 300000) // 每隔 300 秒钟执行一次
+
+// updateWay(img)
}
private fun stopMonitoring() {
isMonitoring = false
startButton.text = "出发"
}
+
@RequiresPermission(
- anyOf = [permission.ACCESS_COARSE_LOCATION, permission.ACCESS_FINE_LOCATION],
+ anyOf = [permission.ACCESS_COARSE_LOCATION,
+ permission.ACCESS_FINE_LOCATION,
+ permission.INTERNET,
+ permission.ACCESS_MEDIA_LOCATION,
+ permission.ACCESS_BACKGROUND_LOCATION,
+ permission.ACCESS_NETWORK_STATE,
+ permission.CAMERA,
+ permission.WRITE_EXTERNAL_STORAGE,
+ permission.READ_EXTERNAL_STORAGE,
+ permission.ACCESS_FINE_LOCATION],
)
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
- if (resultCode == PHOTO_REQUEST_CODE ) {
+ if (resultCode == PHOTO_REQUEST_CODE) {
// doSomeOperations()
}
}
+
private fun checkPermissions(): Boolean {
val requiredPermissions = arrayOf(
+ permission.ACCESS_COARSE_LOCATION,
+ permission.ACCESS_FINE_LOCATION,
+ permission.INTERNET,
+ permission.ACCESS_MEDIA_LOCATION,
+ permission.ACCESS_BACKGROUND_LOCATION,
+ permission.ACCESS_NETWORK_STATE,
permission.CAMERA,
permission.WRITE_EXTERNAL_STORAGE,
+ permission.READ_EXTERNAL_STORAGE,
permission.ACCESS_FINE_LOCATION
)
@@ -123,55 +190,62 @@ class MainActivity : AppCompatActivity() {
permission
) != PackageManager.PERMISSION_GRANTED
) {
- ActivityCompat.requestPermissions(this, requiredPermissions, PERMISSION_REQUEST_CODE)
+ ActivityCompat.requestPermissions(
+ this,
+ requiredPermissions,
+ PERMISSION_REQUEST_CODE
+ )
return false
}
}
return true
}
+
//define the listener
private val locationListener: LocationListener = object : LocationListener {
override fun onLocationChanged(location: Location) {
+ lat = location.latitude.toString()
+ lon = location.longitude.toString()
updateGpsInfo(location)
}
+
override fun onStatusChanged(provider: String, status: Int, extras: Bundle) {}
override fun onProviderEnabled(provider: String) {}
override fun onProviderDisabled(provider: String) {}
}
- private fun createPhotoFile(): File? {
- val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
- val storageDir = getExternalFilesDir(null)
- return File.createTempFile("JPEG_${timeStamp}_", ".jpg", storageDir)
- }
-
- private fun getLocation(){
+ private fun getLocation() {
val locMan = getSystemService(Context.LOCATION_SERVICE) as LocationManager
- val checkCameraPermission = ContextCompat.checkSelfPermission(this, permission.ACCESS_FINE_LOCATION)
+ val checkCameraPermission =
+ ContextCompat.checkSelfPermission(this, permission.ACCESS_FINE_LOCATION)
val checkCallPhonePermission =
ContextCompat.checkSelfPermission(this, permission.ACCESS_COARSE_LOCATION)
if (checkCallPhonePermission != PackageManager.PERMISSION_GRANTED || checkCameraPermission != PackageManager.PERMISSION_GRANTED) {
- ActivityCompat.requestPermissions(this, arrayOf(
- permission.ACCESS_COARSE_LOCATION,
- permission.ACCESS_FINE_LOCATION
- ), 22)
+ ActivityCompat.requestPermissions(
+ this, arrayOf(
+ permission.ACCESS_COARSE_LOCATION,
+ permission.ACCESS_FINE_LOCATION
+ ), 22
+ )
}
try {
// Request location updates
val providers = locMan.getProviders(false)
var provider = LocationManager.NETWORK_PROVIDER
- if(providers.size != 0) {
- if (providers.contains(LocationManager.GPS_PROVIDER)) {
+ if (providers.size != 0) {
+ if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
+ provider = LocationManager.NETWORK_PROVIDER
+ }else if(providers.contains(LocationManager.GPS_PROVIDER)){
provider = LocationManager.GPS_PROVIDER
- }else if (providers.contains(LocationManager.PASSIVE_PROVIDER)){
+ } else if (providers.contains(LocationManager.PASSIVE_PROVIDER)) {
provider = LocationManager.PASSIVE_PROVIDER
}
}
Toast.makeText(baseContext, "使用" + provider + "定位", Toast.LENGTH_SHORT).show()
Log.d(TAG, "==================>>>> get location from gps")
locMan.requestLocationUpdates(provider, 10000L, 100f, locationListener)
- } catch(ex: SecurityException) {
+ } catch (ex: SecurityException) {
Log.d(TAG, "Security Exception, no location available")
}
}
@@ -184,71 +258,23 @@ class MainActivity : AppCompatActivity() {
gpsInfoTextView.text = gpsInfo
}
- private fun uploadPhotoAndGpsInfo(photoFilePath: String, gpsInfo: String) {
- // 在此处实现将照片和GPS信息上传到api.abc.com/report接口的逻辑
- // 可以使用 Retrofit 或其他网络库进行网络请求
- // 将照片转换成 Base64 字符串,然后添加到请求中
- // 请求完成后更新界面上的预览窗口等信息
- GlobalScope.launch(Dispatchers.IO) {
- try {
- val photoFile = File(photoFilePath)
- val photoBytes = ByteArrayOutputStream().use {
- val inputStream = photoFile.inputStream()
- inputStream.copyTo(it)
- it.toByteArray()
- }
-
- val base64Photo = Base64.encodeToString(photoBytes, Base64.DEFAULT)
-
- // 在此处添加上传逻辑
- // 使用 Retrofit 或其他网络库发送照片和GPS信息到api.abc.com/report接口
- // 请注意处理网络请求的结果和错误
- } catch (e: Exception) {
- e.printStackTrace()
- }
- }
- }
-
companion object {
private const val PERMISSION_REQUEST_CODE = 1001
private const val PHOTO_REQUEST_CODE = 1002
private const val TAG = "Travebing"
private const val FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS"
private const val REQUEST_CODE_PERMISSIONS = 10
+ val MEDIA_TYPE_JSON = "application/json; charset=utf-8".toMediaType()
+ val MEDIA_TYPE_MULTIPART = "multipart/form-data".toMediaType()
+ val MEDIA_TYPE_FILE = "application/octet-stream".toMediaType()
}
+
private fun startCamera() {
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener({
- // Used to bind the lifecycle of cameras to the lifecycle owner
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
-
- // Preview
-// val preview = Preview.Builder()
-// .build()
-// .also {
-// it.setSurfaceProvider(viewBinding.viewFinder.surfaceProvider)
-// }
-// val recorder = Recorder.Builder()
-// .setQualitySelector(QualitySelector.from(Quality.HIGHEST,
-// FallbackStrategy.higherQualityOrLowerThan(Quality.SD)))
-// .build()
-// videoCapture = VideoCapture.withOutput(recorder)
-
imageCapture = ImageCapture.Builder().build()
-
- /*
- val imageAnalyzer = ImageAnalysis.Builder().build()
- .also {
- setAnalyzer(
- cameraExecutor,
- LuminosityAnalyzer { luma -> startCamera()
- Log.d(TAG, "Average luminosity: $luma")
- }
- )
- }
- */
-
// Select back camera as a default
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
@@ -258,17 +284,28 @@ class MainActivity : AppCompatActivity() {
// Bind use cases to camera
cameraProvider.bindToLifecycle(
- this, cameraSelector, imageCapture)
+ this, cameraSelector, imageCapture
+ )
- } catch(exc: Exception) {
+ } catch (exc: Exception) {
Log.e(TAG, "Use case binding failed", exc)
}
}, ContextCompat.getMainExecutor(this))
}
- private fun takePhoto() {
+ /**
+ * 单个文件复制
+ */
+ fun copyfile(srcFile: InputStream, destFile: File) {
+ val fos = FileOutputStream(destFile)
+ srcFile.copyTo(fos)
+ fos.close()
+ srcFile.close()
+ }
+
+ private fun takePhoto(): String {
// Get a stable reference of the modifiable image capture use case
- val imageCapture = imageCapture ?: return
+ val imageCapture = imageCapture ?: return ""
Log.d(TAG, "================>>>>> now do capture photo")
// Create time stamped name and MediaStore entry.
val name = SimpleDateFormat(FILENAME_FORMAT, Locale.US)
@@ -276,14 +313,16 @@ class MainActivity : AppCompatActivity() {
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, name)
put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
- put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/CameraX-Image")
+ put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/travebing")
}
// Create output options object which contains file + metadata
val outputOptions = ImageCapture.OutputFileOptions
- .Builder(contentResolver,
+ .Builder(
+ contentResolver,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
- contentValues)
+ contentValues
+ )
.build()
// Set up image capture listener, which is triggered after photo has
@@ -295,16 +334,20 @@ class MainActivity : AppCompatActivity() {
override fun onError(exc: ImageCaptureException) {
Log.e(TAG, "+++++++++++Photo capture failed: ${exc.message}", exc)
}
-
- override fun
- onImageSaved(output: ImageCapture.OutputFileResults){
+ @SuppressLint("Recycle")
+ override fun onImageSaved(output: ImageCapture.OutputFileResults) {
previewImageView.setImageURI(output.savedUri)
val msg = "--------- Photo capture succeeded: ${output.savedUri}"
Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
Log.d(TAG, msg)
+ val resolve = context.contentResolver
+ val uri = Uri.withAppendedPath(output.savedUri, "")
+ val ins:InputStream = resolve.openInputStream(uri)!!
+ updateWay(ins)
}
}
)
+ return name
}
}
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 4e2a9db..6cc9d8b 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -47,7 +47,7 @@
tools:srcCompat="@tools:sample/backgrounds/scenic" />
+
+
+
\ No newline at end of file