Skip to content

Commit

Permalink
Merge branch 'master' into github-action-unit-tests
Browse files Browse the repository at this point in the history
  • Loading branch information
shobhitagarwal1612 authored Aug 19, 2024
2 parents f7bee2c + 614664b commit 7e396e9
Showing 1 changed file with 41 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@
*/
package com.google.android.ground.ui.datacollection.tasks.photo

import android.content.Context
import android.content.res.Resources
import android.graphics.Bitmap
import android.graphics.Matrix
import android.media.ExifInterface
import android.net.Uri
import androidx.lifecycle.LiveData
import androidx.lifecycle.asLiveData
Expand All @@ -25,14 +29,17 @@ import com.google.android.ground.persistence.remote.firebase.FirebaseStorageMana
import com.google.android.ground.repository.UserMediaRepository
import com.google.android.ground.ui.datacollection.tasks.AbstractTaskViewModel
import com.google.android.ground.ui.util.BitmapUtil
import dagger.hilt.android.qualifiers.ApplicationContext
import java.io.IOException
import java.lang.UnsupportedOperationException
import javax.inject.Inject
import kotlinx.coroutines.flow.map
import timber.log.Timber

class PhotoTaskViewModel
@Inject
constructor(
@ApplicationContext private val context: Context,
private val userMediaRepository: UserMediaRepository,
private val bitmapUtil: BitmapUtil,
resources: Resources,
Expand All @@ -50,6 +57,15 @@ constructor(
taskTaskData.map { userMediaRepository.getDownloadUrl(it?.getDetailsText()) }.asLiveData()
val isPhotoPresent: LiveData<Boolean> = taskTaskData.map { it.isNotNullOrEmpty() }.asLiveData()

private fun rotateBitmap(bitmap: Bitmap, rotateDegrees: Float): Bitmap {
val matrix = Matrix()
// Rotate iff rotation is non-zero.
if (rotateDegrees != 0f) {
matrix.postRotate(rotateDegrees)
}
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true)
}

/**
* Saves photo data stored on an on-device URI in Ground-associated storage and prepares it for
* inclusion in a data collection submission.
Expand All @@ -59,7 +75,9 @@ constructor(
requireNotNull(currentTask) { "Photo captured but no task waiting for the result" }

try {
val bitmap = bitmapUtil.fromUri(uri)
val orientation = getOrientationFromExif(uri)
val rotateDegrees = getRotationDegrees(orientation)
val bitmap = rotateBitmap(bitmapUtil.fromUri(uri), rotateDegrees)
val file = userMediaRepository.savePhoto(bitmap, currentTask)
userMediaRepository.addImageToGallery(file.absolutePath, file.name)
val remoteFilename = FirebaseStorageManager.getRemoteMediaPath(surveyId, file.absolutePath)
Expand All @@ -68,4 +86,26 @@ constructor(
Timber.e(e, "Error getting photo selected from storage")
}
}

/**
* Returns the number of degrees a photo should be rotated based on the value of its orientation
* EXIF tag.
*/
private fun getRotationDegrees(orientation: Int): Float =
when (orientation) {
ExifInterface.ORIENTATION_NORMAL -> 0f
ExifInterface.ORIENTATION_ROTATE_90 -> 90f
ExifInterface.ORIENTATION_ROTATE_180 -> 180f
ExifInterface.ORIENTATION_ROTATE_270 -> 270f
else -> throw UnsupportedOperationException("Unsupported photo orientation $orientation")
}

/** Returns the EXIF orientation attribute of the JPEG image at the specified URI. */
private fun getOrientationFromExif(uri: Uri): Int {
val inputStream =
context.contentResolver.openInputStream(uri)
?: throw IOException("Content resolver returned null for $uri")
val exif = ExifInterface(inputStream)
return exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)
}
}

0 comments on commit 7e396e9

Please sign in to comment.