diff --git a/data/src/main/java/com/moez/QKSMS/repository/ImageRepositoryImpl.kt b/data/src/main/java/com/moez/QKSMS/repository/ImageRepositoryImpl.kt new file mode 100644 index 000000000..a4aee3642 --- /dev/null +++ b/data/src/main/java/com/moez/QKSMS/repository/ImageRepositoryImpl.kt @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2017 Moez Bhatti + * + * This file is part of QKSMS. + * + * QKSMS is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * QKSMS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with QKSMS. If not, see . + */ +package com.moez.QKSMS.repository + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.Matrix +import android.net.Uri +import androidx.exifinterface.media.ExifInterface +import javax.inject.Inject + +class ImageRepositoryImpl @Inject constructor(private val context: Context) : ImageRepository { + + override fun loadImage(uri: Uri, width: Int, height: Int): Bitmap? { + val orientation = context.contentResolver.openInputStream(uri)?.use(::ExifInterface) + ?.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL) + val rotated = orientation == ExifInterface.ORIENTATION_ROTATE_90 + || orientation == ExifInterface.ORIENTATION_ROTATE_270 + + // Determine the dimensions + val dimensionsOptions = BitmapFactory.Options().apply { inJustDecodeBounds = true } + BitmapFactory.decodeStream(context.contentResolver.openInputStream(uri), null, dimensionsOptions) + val srcWidth = if (rotated) dimensionsOptions.outHeight else dimensionsOptions.outWidth + val srcHeight = if (rotated) dimensionsOptions.outWidth else dimensionsOptions.outHeight + + // If we get the dimensions and they don't exceed the max size, we don't need to scale + val inputStream = context.contentResolver.openInputStream(uri) + val bitmap = if ((width == 0 || srcWidth < width) && (height == 0 || srcHeight < height)) { + BitmapFactory.decodeStream(inputStream) + } else { + val widthScaleFactor = width.toDouble() / srcWidth + val heightScaleFactor = height.toDouble() / srcHeight + val options = when { + widthScaleFactor > heightScaleFactor -> BitmapFactory.Options().apply { + inScaled = true + inSampleSize = 4 + inDensity = srcHeight + inTargetDensity = height * inSampleSize + } + + else -> BitmapFactory.Options().apply { + inScaled = true + inSampleSize = 4 + inDensity = srcWidth + inTargetDensity = width * inSampleSize + } + } + BitmapFactory.decodeStream(inputStream, null, options) ?: return null + } + + return when (orientation) { + ExifInterface.ORIENTATION_ROTATE_90 -> rotateBitmap(bitmap, 90f) + ExifInterface.ORIENTATION_ROTATE_180 -> rotateBitmap(bitmap, 180f) + ExifInterface.ORIENTATION_ROTATE_270 -> rotateBitmap(bitmap, 270f) + else -> bitmap + } + } + + private fun rotateBitmap(bitmap: Bitmap, degree: Float): Bitmap { + val w = bitmap.width + val h = bitmap.height + + val mtx = Matrix() + mtx.postRotate(degree) + + return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true) + } + +} diff --git a/data/src/main/java/com/moez/QKSMS/repository/ImageRepostoryImpl.kt b/data/src/main/java/com/moez/QKSMS/repository/ImageRepostoryImpl.kt deleted file mode 100644 index 06bc586f4..000000000 --- a/data/src/main/java/com/moez/QKSMS/repository/ImageRepostoryImpl.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2017 Moez Bhatti - * - * This file is part of QKSMS. - * - * QKSMS is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * QKSMS is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with QKSMS. If not, see . - */ -package com.moez.QKSMS.repository - -import android.content.Context -import android.graphics.Bitmap -import android.graphics.BitmapFactory -import android.graphics.Matrix -import android.net.Uri -import androidx.exifinterface.media.ExifInterface -import javax.inject.Inject - -class ImageRepostoryImpl @Inject constructor(private val context: Context) : ImageRepository { - - override fun loadImage(uri: Uri): Bitmap? { - val exif = context.contentResolver.openInputStream(uri)?.let(::ExifInterface) - val bitmap = BitmapFactory.decodeStream(context.contentResolver.openInputStream(uri)) - val orientation = exif?.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL) - - return when (orientation) { - ExifInterface.ORIENTATION_ROTATE_90 -> rotateBitmap(bitmap, 90f) - ExifInterface.ORIENTATION_ROTATE_180 -> rotateBitmap(bitmap, 180f) - ExifInterface.ORIENTATION_ROTATE_270 -> rotateBitmap(bitmap, 270f) - else -> bitmap - } - } - - private fun rotateBitmap(bitmap: Bitmap, degree: Float): Bitmap { - val w = bitmap.width - val h = bitmap.height - - val mtx = Matrix() - mtx.postRotate(degree) - - return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true) - } - -} diff --git a/data/src/main/java/com/moez/QKSMS/repository/MessageRepositoryImpl.kt b/data/src/main/java/com/moez/QKSMS/repository/MessageRepositoryImpl.kt index ef777487f..c25e857eb 100644 --- a/data/src/main/java/com/moez/QKSMS/repository/MessageRepositoryImpl.kt +++ b/data/src/main/java/com/moez/QKSMS/repository/MessageRepositoryImpl.kt @@ -303,6 +303,12 @@ class MessageRepositoryImpl @Inject constructor( parts += MMSPart("text", ContentType.TEXT_PLAIN, signedBody.toByteArray()) } + val smsManager = subId.takeIf { it != -1 } + ?.let(SmsManagerFactory::createSmsManager) + ?: SmsManager.getDefault() + val width = smsManager.carrierConfigValues.getInt(SmsManager.MMS_CONFIG_MAX_IMAGE_WIDTH) + val height = smsManager.carrierConfigValues.getInt(SmsManager.MMS_CONFIG_MAX_IMAGE_HEIGHT) + // Add the GIFs as attachments parts += attachments .mapNotNull { attachment -> attachment as? Attachment.Image } @@ -317,7 +323,7 @@ class MessageRepositoryImpl @Inject constructor( .mapNotNull { attachment -> attachment as? Attachment.Image } .filter { attachment -> !attachment.isGif(context) } .mapNotNull { attachment -> attachment.getUri() } - .mapNotNull { uri -> tryOrNull { imageRepository.loadImage(uri) } } + .mapNotNull { uri -> tryOrNull { imageRepository.loadImage(uri, width, height) } } .also { totalImageBytes = it.sumBy { it.allocationByteCount } } .map { bitmap -> val byteRatio = bitmap.allocationByteCount / totalImageBytes.toFloat() diff --git a/domain/src/main/java/com/moez/QKSMS/repository/ImageRepository.kt b/domain/src/main/java/com/moez/QKSMS/repository/ImageRepository.kt index 70c6ecbb3..da02a1f8b 100644 --- a/domain/src/main/java/com/moez/QKSMS/repository/ImageRepository.kt +++ b/domain/src/main/java/com/moez/QKSMS/repository/ImageRepository.kt @@ -23,6 +23,6 @@ import android.net.Uri interface ImageRepository { - fun loadImage(uri: Uri): Bitmap? + fun loadImage(uri: Uri, width: Int, height: Int): Bitmap? } diff --git a/presentation/src/main/java/com/moez/QKSMS/injection/AppModule.kt b/presentation/src/main/java/com/moez/QKSMS/injection/AppModule.kt index 18d9cf20e..8862b1894 100644 --- a/presentation/src/main/java/com/moez/QKSMS/injection/AppModule.kt +++ b/presentation/src/main/java/com/moez/QKSMS/injection/AppModule.kt @@ -70,7 +70,7 @@ import com.moez.QKSMS.repository.ContactRepositoryImpl import com.moez.QKSMS.repository.ConversationRepository import com.moez.QKSMS.repository.ConversationRepositoryImpl import com.moez.QKSMS.repository.ImageRepository -import com.moez.QKSMS.repository.ImageRepostoryImpl +import com.moez.QKSMS.repository.ImageRepositoryImpl import com.moez.QKSMS.repository.MessageRepository import com.moez.QKSMS.repository.MessageRepositoryImpl import com.moez.QKSMS.repository.ScheduledMessageRepository @@ -185,7 +185,7 @@ class AppModule(private var application: Application) { fun provideConversationRepository(repository: ConversationRepositoryImpl): ConversationRepository = repository @Provides - fun provideImageRepository(repository: ImageRepostoryImpl): ImageRepository = repository + fun provideImageRepository(repository: ImageRepositoryImpl): ImageRepository = repository @Provides fun provideMessageRepository(repository: MessageRepositoryImpl): MessageRepository = repository