diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7a1883f..42762a3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,12 @@ + + + + + + + android:value="${MAPS_API_KEY}" /> - + android:exported="false" /> \ No newline at end of file diff --git a/app/src/main/java/com/sample/otuslocationmapshw/MapsActivity.kt b/app/src/main/java/com/sample/otuslocationmapshw/MapsActivity.kt index c063bfb..d20c60b 100644 --- a/app/src/main/java/com/sample/otuslocationmapshw/MapsActivity.kt +++ b/app/src/main/java/com/sample/otuslocationmapshw/MapsActivity.kt @@ -31,7 +31,7 @@ class MapsActivity : AppCompatActivity(), OnMapReadyCallback { ActivityResultContracts.StartActivityForResult() ) { if (it.resultCode == CameraActivity.SUCCESS_RESULT_CODE) { - // TODO("Обновить точки на карте при получении результата от камеры") + showPreviewsOnMap() } } @@ -41,9 +41,8 @@ class MapsActivity : AppCompatActivity(), OnMapReadyCallback { binding = ActivityMapsBinding.inflate(layoutInflater) setContentView(binding.root) - val mapFragment = supportFragmentManager - .findFragmentById(R.id.map) as SupportMapFragment - // TODO("Вызвать инициализацию карты") + val mapFragment = supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment + mapFragment.getMapAsync(this) } override fun onCreateOptionsMenu(menu: Menu?): Boolean { @@ -57,6 +56,7 @@ class MapsActivity : AppCompatActivity(), OnMapReadyCallback { cameraForResultLauncher.launch(Intent(this, CameraActivity::class.java)) true } + else -> { super.onOptionsItemSelected(item) } @@ -72,23 +72,24 @@ class MapsActivity : AppCompatActivity(), OnMapReadyCallback { private fun showPreviewsOnMap() { map.clear() val folder = File("${filesDir.absolutePath}/photos/") + var lastPoint: LatLng? = null folder.listFiles()?.forEach { val exifInterface = ExifInterface(it) val location = locationDataUtils.getLocationFromExif(exifInterface) val point = LatLng(location.latitude, location.longitude) + lastPoint = point val pinBitmap = Bitmap.createScaledBitmap( BitmapFactory.decodeFile( - it.path, - BitmapFactory.Options().apply { + it.path, BitmapFactory.Options().apply { inPreferredConfig = Bitmap.Config.ARGB_8888 }), 64, 64, false ) - // TODO("Указать pinBitmap как иконку для маркера") map.addMarker( - MarkerOptions() - .position(point) + MarkerOptions().position(point).icon(BitmapDescriptorFactory.fromBitmap(pinBitmap)) ) - // TODO("Передвинуть карту к местоположению последнего фото") + lastPoint?.let { + map.animateCamera(CameraUpdateFactory.newLatLngZoom(it, 10f)) + } } } } \ No newline at end of file diff --git a/app/src/main/java/com/sample/otuslocationmapshw/camera/CameraActivity.kt b/app/src/main/java/com/sample/otuslocationmapshw/camera/CameraActivity.kt index 076ade5..df49487 100644 --- a/app/src/main/java/com/sample/otuslocationmapshw/camera/CameraActivity.kt +++ b/app/src/main/java/com/sample/otuslocationmapshw/camera/CameraActivity.kt @@ -26,6 +26,7 @@ import java.io.File import java.text.SimpleDateFormat import java.util.Date import java.util.Locale +import kotlin.invoke import kotlin.math.abs class CameraActivity : AppCompatActivity() { @@ -58,9 +59,8 @@ class CameraActivity : AppCompatActivity() { fusedLocationClient = LocationServices.getFusedLocationProviderClient(this) cameraProviderFuture = ProcessCameraProvider.getInstance(this) - // TODO("Получить экземпляр SensorManager") - // TODO("Добавить проверку на наличие датчика акселерометра и присвоить значение tiltSensor") - tiltSensor = TODO("Get tilt sensor") + sensorManager = getSystemService(SENSOR_SERVICE) as SensorManager + tiltSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) cameraProviderFuture.addListener({ cameraProvider = cameraProviderFuture.get() }, ContextCompat.getMainExecutor(this)) @@ -81,14 +81,24 @@ class CameraActivity : AppCompatActivity() { } } - // TODO("Подписаться на получение событий обновления датчика") + override fun onResume() { + super.onResume() + tiltSensor?.let { + sensorManager.registerListener( + sensorEventListener, + it, + SensorManager.SENSOR_DELAY_UI + ) + } + } - // TODO("Остановить получение событий от датчика") + override fun onPause() { + super.onPause() + sensorManager.unregisterListener(sensorEventListener) + } override fun onRequestPermissionsResult( - requestCode: Int, - permissions: Array, - grantResults: IntArray + requestCode: Int, permissions: Array, grantResults: IntArray ) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode == REQUEST_CODE_PERMISSIONS) { @@ -96,9 +106,7 @@ class CameraActivity : AppCompatActivity() { startCamera() } else { Toast.makeText( - this, - "Permissions not granted by the user.", - Toast.LENGTH_SHORT + this, "Permissions not granted by the user.", Toast.LENGTH_SHORT ).show() finish() } @@ -115,21 +123,42 @@ class CameraActivity : AppCompatActivity() { if (!folder.exists()) { folder.mkdirs() } - val filePath = folderPath + SimpleDateFormat(FILENAME_FORMAT, Locale.getDefault()).format(Date()) + val filePath = + folderPath + SimpleDateFormat(FILENAME_FORMAT, Locale.getDefault()).format(Date()) - // TODO("4. Добавить установку местоположения в метаданные фото") - val outputFileOptions = ImageCapture.OutputFileOptions.Builder(File(filePath)) - .build() - - // TODO("Добавить вызов CameraX для фото") - // TODO("Вывести Toast о том, что фото успешно сохранено и закрыть текущее активити c указанием кода результата SUCCESS_RESULT_CODE") - // imageCapture... + val metadata = ImageCapture.Metadata().apply { + this.location = location + } + val outputFileOptions = + ImageCapture.OutputFileOptions.Builder(File(filePath)).setMetadata(metadata).build() + + imageCapture.takePicture( + outputFileOptions, + ContextCompat.getMainExecutor(this), + object : ImageCapture.OnImageSavedCallback { + override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) { + Toast.makeText(baseContext, "Фото успешно сохранено", Toast.LENGTH_SHORT) + .show() + setResult(SUCCESS_RESULT_CODE) + finish() + } + + override fun onError(exception: androidx.camera.core.ImageCaptureException) { + Log.e("CameraXApp", "Ошибка при съемке: ${exception.message}", exception) + Toast.makeText(baseContext, "Ошибка сохранения фото", Toast.LENGTH_SHORT) + .show() + } + }) } } @SuppressLint("MissingPermission") private fun getLastLocation(callback: (location: Location?) -> Unit) { - // TODO("Добавить получение местоположения от fusedLocationClient и передать результат в callback после получения") + fusedLocationClient.lastLocation.addOnSuccessListener { location: Location? -> + callback.invoke(location) + }.addOnFailureListener { + callback.invoke(null) + } } private fun startCamera() { @@ -137,11 +166,9 @@ class CameraActivity : AppCompatActivity() { cameraProviderFuture.addListener({ val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get() - val preview = Preview.Builder() - .build() - .also { - it.setSurfaceProvider(binding.cameraPreview.surfaceProvider) - } + val preview = Preview.Builder().build().also { + it.setSurfaceProvider(binding.cameraPreview.surfaceProvider) + } imageCapture = ImageCapture.Builder().build() @@ -168,9 +195,10 @@ class CameraActivity : AppCompatActivity() { private const val TAG = "CameraXApp" private const val FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS" private const val REQUEST_CODE_PERMISSIONS = 10 - // TODO("Указать набор требуемых разрешений") private val REQUIRED_PERMISSIONS: Array = mutableListOf( - // TODO("Добавить требуемые разрешения") + android.Manifest.permission.CAMERA, + android.Manifest.permission.ACCESS_FINE_LOCATION, + android.Manifest.permission.ACCESS_COARSE_LOCATION ).toTypedArray() const val SUCCESS_RESULT_CODE = 15 diff --git a/build.gradle b/build.gradle index 2938249..5e39d76 100644 --- a/build.gradle +++ b/build.gradle @@ -1,4 +1,10 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. +buildscript { + dependencies { + classpath("com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin:2.0.1") + } +} + plugins { id 'com.android.application' version '8.7.3' apply false id 'com.android.library' version '8.7.3' apply false