1
0
mirror of https://github.com/KokaKiwi/BarInsta synced 2024-09-27 21:27:30 +00:00

Convert DownloadWorker to kotlin

This commit is contained in:
Ammar Githam 2021-06-02 08:09:22 +09:00
parent 9e65ee9d27
commit 5756f055d9
2 changed files with 303 additions and 315 deletions

View File

@ -172,7 +172,6 @@ dependencies {
implementation "androidx.navigation:navigation-ui:$nav_version" implementation "androidx.navigation:navigation-ui:$nav_version"
implementation "androidx.constraintlayout:constraintlayout:2.0.4" implementation "androidx.constraintlayout:constraintlayout:2.0.4"
implementation "androidx.preference:preference:1.1.1" implementation "androidx.preference:preference:1.1.1"
implementation "androidx.work:work-runtime:2.5.0"
implementation 'androidx.palette:palette:1.0.0' implementation 'androidx.palette:palette:1.0.0'
implementation 'com.google.guava:guava:27.0.1-android' implementation 'com.google.guava:guava:27.0.1-android'
@ -204,6 +203,11 @@ dependencies {
implementation "androidx.emoji:emoji:$emoji_compat_version" implementation "androidx.emoji:emoji:$emoji_compat_version"
implementation "androidx.emoji:emoji-appcompat:$emoji_compat_version" implementation "androidx.emoji:emoji-appcompat:$emoji_compat_version"
// Work
def work_version = '2.5.0'
implementation "androidx.work:work-runtime:$work_version"
implementation "androidx.work:work-runtime-ktx:$work_version"
implementation 'com.facebook.fresco:fresco:2.3.0' implementation 'com.facebook.fresco:fresco:2.3.0'
implementation 'com.facebook.fresco:animated-webp:2.3.0' implementation 'com.facebook.fresco:animated-webp:2.3.0'
implementation 'com.facebook.fresco:webpsupport:2.3.0' implementation 'com.facebook.fresco:webpsupport:2.3.0'

View File

@ -1,399 +1,383 @@
package awais.instagrabber.workers; package awais.instagrabber.workers
import android.app.Notification; import android.app.Notification
import android.app.PendingIntent; import android.app.PendingIntent
import android.content.ContentResolver; import android.content.ContentResolver
import android.content.Context; import android.content.Context
import android.content.Intent; import android.content.Intent
import android.graphics.Bitmap; import android.graphics.Bitmap
import android.media.MediaMetadataRetriever; import android.media.MediaMetadataRetriever
import android.media.MediaScannerConnection; import android.media.MediaScannerConnection
import android.net.Uri; import android.net.Uri
import android.os.Build; import android.os.Build
import android.os.Handler; import android.os.Handler
import android.os.Looper; import android.os.Looper
import android.util.Log; import android.util.Log
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.FileProvider
import androidx.work.CoroutineWorker
import androidx.work.Data
import androidx.work.ForegroundInfo
import androidx.work.WorkerParameters
import awais.instagrabber.BuildConfig
import awais.instagrabber.R
import awais.instagrabber.services.DeleteImageIntentService
import awais.instagrabber.utils.BitmapUtils
import awais.instagrabber.utils.Constants.DOWNLOAD_CHANNEL_ID
import awais.instagrabber.utils.Constants.NOTIF_GROUP_NAME
import awais.instagrabber.utils.DownloadUtils
import awais.instagrabber.utils.TextUtils.isEmpty
import awais.instagrabber.utils.Utils
import awais.instagrabber.utils.extensions.TAG
import com.google.gson.Gson
import com.google.gson.JsonSyntaxException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.apache.commons.imaging.formats.jpeg.iptc.JpegIptcRewriter
import java.io.BufferedInputStream
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.net.URL
import java.util.*
import java.util.concurrent.ExecutionException
import kotlin.math.abs
import androidx.annotation.NonNull; class DownloadWorker(context: Context, workerParams: WorkerParameters) : CoroutineWorker(context, workerParams) {
import androidx.annotation.Nullable; private val notificationManager: NotificationManagerCompat = NotificationManagerCompat.from(context)
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import androidx.core.content.FileProvider;
import androidx.work.Data;
import androidx.work.ForegroundInfo;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
import com.google.gson.Gson; override suspend fun doWork(): Result {
import com.google.gson.JsonSyntaxException; val downloadRequestFilePath = inputData.getString(KEY_DOWNLOAD_REQUEST_JSON)
if (downloadRequestFilePath.isNullOrBlank()) {
import org.apache.commons.imaging.formats.jpeg.iptc.JpegIptcRewriter; return Result.failure(Data.Builder()
.putString("error", "downloadRequest is empty or null")
import java.io.BufferedInputStream; .build())
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import awais.instagrabber.BuildConfig;
import awais.instagrabber.R;
import awais.instagrabber.services.DeleteImageIntentService;
import awais.instagrabber.utils.BitmapUtils;
import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.DownloadUtils;
import awais.instagrabber.utils.TextUtils;
import awais.instagrabber.utils.Utils;
import static awais.instagrabber.utils.BitmapUtils.THUMBNAIL_SIZE;
import static awais.instagrabber.utils.Constants.DOWNLOAD_CHANNEL_ID;
import static awais.instagrabber.utils.Constants.NOTIF_GROUP_NAME;
public class DownloadWorker extends Worker {
private static final String TAG = "DownloadWorker";
private static final String DOWNLOAD_GROUP = "DOWNLOAD_GROUP";
public static final String PROGRESS = "PROGRESS";
public static final String URL = "URL";
public static final String KEY_DOWNLOAD_REQUEST_JSON = "download_request_json";
public static final int DOWNLOAD_NOTIFICATION_INTENT_REQUEST_CODE = 2020;
public static final int DELETE_IMAGE_REQUEST_CODE = 2030;
private final NotificationManagerCompat notificationManager;
public DownloadWorker(@NonNull final Context context, @NonNull final WorkerParameters workerParams) {
super(context, workerParams);
notificationManager = NotificationManagerCompat.from(context);
}
@NonNull
@Override
public Result doWork() {
final String downloadRequestFilePath = getInputData().getString(KEY_DOWNLOAD_REQUEST_JSON);
if (TextUtils.isEmpty(downloadRequestFilePath)) {
return Result.failure(new Data.Builder()
.putString("error", "downloadRequest is empty or null")
.build());
} }
final String downloadRequestString; val downloadRequestString: String
final File requestFile = new File(downloadRequestFilePath); val requestFile = File(downloadRequestFilePath)
try (Scanner scanner = new Scanner(requestFile)) {
downloadRequestString = scanner.useDelimiter("\\A").next();
} catch (Exception e) {
Log.e(TAG, "doWork: ", e);
return Result.failure(new Data.Builder()
.putString("error", e.getLocalizedMessage())
.build());
}
if (TextUtils.isEmpty(downloadRequestString)) {
return Result.failure(new Data.Builder()
.putString("error", "downloadRequest is empty or null")
.build());
}
final DownloadRequest downloadRequest;
try { try {
downloadRequest = new Gson().fromJson(downloadRequestString, DownloadRequest.class); downloadRequestString = requestFile.bufferedReader().use { it.readText() }
} catch (JsonSyntaxException e) { } catch (e: Exception) {
Log.e(TAG, "doWork", e); Log.e(TAG, "doWork: ", e)
return Result.failure(new Data.Builder() return Result.failure(Data.Builder()
.putString("error", e.getLocalizedMessage()) .putString("error", e.localizedMessage)
.build()); .build())
} }
if (downloadRequest == null) { if (downloadRequestString.isBlank()) {
return Result.failure(new Data.Builder() return Result.failure(Data.Builder()
.putString("error", "downloadRequest is null") .putString("error", "downloadRequest is empty")
.build()); .build())
} }
final Map<String, String> urlToFilePathMap = downloadRequest.getUrlToFilePathMap(); val downloadRequest: DownloadRequest = try {
download(urlToFilePathMap); Gson().fromJson(downloadRequestString, DownloadRequest::class.java)
new Handler(Looper.getMainLooper()).postDelayed(() -> showSummary(urlToFilePathMap), 500); } catch (e: JsonSyntaxException) {
final boolean deleted = requestFile.delete(); Log.e(TAG, "doWork", e)
return Result.failure(Data.Builder()
.putString("error", e.localizedMessage)
.build())
} ?: return Result.failure(Data.Builder()
.putString("error", "downloadRequest is null")
.build())
val urlToFilePathMap = downloadRequest.urlToFilePathMap
download(urlToFilePathMap)
Handler(Looper.getMainLooper()).postDelayed({ showSummary(urlToFilePathMap) }, 500)
val deleted = requestFile.delete()
if (!deleted) { if (!deleted) {
Log.w(TAG, "doWork: requestFile not deleted!"); Log.w(TAG, "doWork: requestFile not deleted!")
} }
return Result.success(); return Result.success()
} }
private void download(final Map<String, String> urlToFilePathMap) { private suspend fun download(urlToFilePathMap: Map<String, String>) {
final int notificationId = getNotificationId(); val notificationId = notificationId
final Set<Map.Entry<String, String>> entries = urlToFilePathMap.entrySet(); val entries = urlToFilePathMap.entries
int count = 1; var count = 1
final int total = urlToFilePathMap.size(); val total = urlToFilePathMap.size
for (final Map.Entry<String, String> urlAndFilePath : entries) { for ((url, value) in entries) {
final String url = urlAndFilePath.getKey(); updateDownloadProgress(notificationId, count, total, 0f)
updateDownloadProgress(notificationId, count, total, 0); withContext(Dispatchers.IO) {
download(notificationId, count, total, url, urlAndFilePath.getValue()); download(notificationId, count, total, url, value)
count++; }
count++
} }
} }
private int getNotificationId() { private val notificationId: Int
return Math.abs(getId().hashCode()); get() = abs(id.hashCode())
}
private void download(final int notificationId, private fun download(
final int position, notificationId: Int,
final int total, position: Int,
final String url, total: Int,
final String filePath) { url: String,
final boolean isJpg = filePath.endsWith("jpg"); filePath: String,
) {
val isJpg = filePath.endsWith("jpg")
// using temp file approach to remove IPTC so that download progress can be reported // using temp file approach to remove IPTC so that download progress can be reported
final File outFile = isJpg ? DownloadUtils.getTempFile() : new File(filePath); val outFile = if (isJpg) DownloadUtils.getTempFile() else File(filePath)
try { try {
final URLConnection urlConnection = new URL(url).openConnection(); val urlConnection = URL(url).openConnection()
final long fileSize = Build.VERSION.SDK_INT >= 24 ? urlConnection.getContentLengthLong() : val fileSize = if (Build.VERSION.SDK_INT >= 24) urlConnection.contentLengthLong else urlConnection.contentLength.toLong()
urlConnection.getContentLength(); var totalRead = 0f
float totalRead = 0; try {
try (final BufferedInputStream bis = new BufferedInputStream(urlConnection.getInputStream()); BufferedInputStream(urlConnection.getInputStream()).use { bis ->
final FileOutputStream fos = new FileOutputStream(outFile)) { FileOutputStream(outFile).use { fos ->
final byte[] buffer = new byte[0x2000]; val buffer = ByteArray(0x2000)
int count; var count: Int
while ((count = bis.read(buffer, 0, 0x2000)) != -1) { while (bis.read(buffer, 0, 0x2000).also { count = it } != -1) {
totalRead = totalRead + count; totalRead += count
fos.write(buffer, 0, count); fos.write(buffer, 0, count)
setProgressAsync(new Data.Builder().putString(URL, url) setProgressAsync(Data.Builder().putString(URL, url)
.putFloat(PROGRESS, totalRead * 100f / fileSize) .putFloat(PROGRESS, totalRead * 100f / fileSize)
.build()); .build())
updateDownloadProgress(notificationId, position, total, totalRead * 100f / fileSize); updateDownloadProgress(notificationId, position, total, totalRead * 100f / fileSize)
}
fos.flush()
}
} }
fos.flush(); } catch (e: Exception) {
} catch (final Exception e) { Log.e(TAG, "Error while writing data from url: " + url + " to file: " + outFile.absolutePath, e)
Log.e(TAG, "Error while writing data from url: " + url + " to file: " + outFile.getAbsolutePath(), e);
} }
if (isJpg) { if (isJpg) {
final File finalFile = new File(filePath); val finalFile = File(filePath)
try (FileInputStream fis = new FileInputStream(outFile); try {
FileOutputStream fos = new FileOutputStream(finalFile)) { FileInputStream(outFile).use { fis ->
final JpegIptcRewriter jpegIptcRewriter = new JpegIptcRewriter(); FileOutputStream(finalFile).use { fos ->
jpegIptcRewriter.removeIPTC(fis, fos); val jpegIptcRewriter = JpegIptcRewriter()
} catch (Exception e) { jpegIptcRewriter.removeIPTC(fis, fos)
}
}
} catch (e: Exception) {
Log.e(TAG, "Error while removing iptc: url: " + url Log.e(TAG, "Error while removing iptc: url: " + url
+ ", tempFile: " + outFile.getAbsolutePath() + ", tempFile: " + outFile.absolutePath
+ ", finalFile: " + finalFile.getAbsolutePath(), e); + ", finalFile: " + finalFile.absolutePath, e)
} }
final boolean deleted = outFile.delete(); val deleted = outFile.delete()
if (!deleted) { if (!deleted) {
Log.w(TAG, "download: tempFile not deleted!"); Log.w(TAG, "download: tempFile not deleted!")
} }
} }
} catch (final Exception e) { } catch (e: Exception) {
Log.e(TAG, "Error while downloading: " + url, e); Log.e(TAG, "Error while downloading: $url", e)
} }
setProgressAsync(new Data.Builder().putString(URL, url) setProgressAsync(Data.Builder().putString(URL, url)
.putFloat(PROGRESS, 100) .putFloat(PROGRESS, 100f)
.build()); .build())
updateDownloadProgress(notificationId, position, total, 100); updateDownloadProgress(notificationId, position, total, 100f)
} }
private void updateDownloadProgress(final int notificationId, private fun updateDownloadProgress(
final int position, notificationId: Int,
final int total, position: Int,
final float percent) { total: Int,
final Notification notification = createProgressNotification(position, total, percent); percent: Float,
) {
val notification = createProgressNotification(position, total, percent)
try { try {
if (notification == null) { if (notification == null) {
notificationManager.cancel(notificationId); notificationManager.cancel(notificationId)
return; return
} }
setForegroundAsync(new ForegroundInfo(notificationId, notification)).get(); setForegroundAsync(ForegroundInfo(notificationId, notification)).get()
} catch (ExecutionException | InterruptedException e) { } catch (e: ExecutionException) {
Log.e(TAG, "updateDownloadProgress", e); Log.e(TAG, "updateDownloadProgress", e)
} catch (e: InterruptedException) {
Log.e(TAG, "updateDownloadProgress", e)
} }
} }
private Notification createProgressNotification(final int position, final int total, final float percent) { private fun createProgressNotification(position: Int, total: Int, percent: Float): Notification? {
final Context context = getApplicationContext(); val context = applicationContext
boolean ongoing = true; var ongoing = true
int totalPercent; val totalPercent: Int
if (position == total && percent == 100) { if (position == total && percent == 100f) {
ongoing = false; ongoing = false
totalPercent = 100; totalPercent = 100
} else { } else {
totalPercent = (int) ((100f * (position - 1) / total) + (1f / total) * (percent)); totalPercent = (100f * (position - 1) / total + 1f / total * percent).toInt()
} }
if (totalPercent == 100) { if (totalPercent == 100) {
return null; return null
} }
// Log.d(TAG, "createProgressNotification: position: " + position // Log.d(TAG, "createProgressNotification: position: " + position
// + ", total: " + total // + ", total: " + total
// + ", percent: " + percent // + ", percent: " + percent
// + ", totalPercent: " + totalPercent); // + ", totalPercent: " + totalPercent);
final NotificationCompat.Builder builder = new NotificationCompat.Builder(context, Constants.DOWNLOAD_CHANNEL_ID) val builder = NotificationCompat.Builder(context, DOWNLOAD_CHANNEL_ID)
.setCategory(NotificationCompat.CATEGORY_PROGRESS) .setCategory(NotificationCompat.CATEGORY_PROGRESS)
.setSmallIcon(R.drawable.ic_download) .setSmallIcon(R.drawable.ic_download)
.setOngoing(ongoing) .setOngoing(ongoing)
.setProgress(100, totalPercent, totalPercent < 0) .setProgress(100, totalPercent, totalPercent < 0)
.setAutoCancel(false) .setAutoCancel(false)
.setOnlyAlertOnce(true) .setOnlyAlertOnce(true)
.setContentTitle(context.getString(R.string.downloader_downloading_post)); .setContentTitle(context.getString(R.string.downloader_downloading_post))
if (total > 1) { if (total > 1) {
builder.setContentText(context.getString(R.string.downloader_downloading_child, position, total)); builder.setContentText(context.getString(R.string.downloader_downloading_child, position, total))
} }
return builder.build(); return builder.build()
} }
private void showSummary(final Map<String, String> urlToFilePathMap) { private fun showSummary(urlToFilePathMap: Map<String, String>?) {
final Context context = getApplicationContext(); val context = applicationContext
final Collection<String> filePaths = urlToFilePathMap.values(); val filePaths = urlToFilePathMap!!.values
final List<NotificationCompat.Builder> notifications = new LinkedList<>(); val notifications: MutableList<NotificationCompat.Builder> = LinkedList()
final List<Integer> notificationIds = new LinkedList<>(); val notificationIds: MutableList<Int> = LinkedList()
int count = 1; var count = 1
for (final String filePath : filePaths) { for (filePath in filePaths) {
final File file = new File(filePath); val file = File(filePath)
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(file))); context.sendBroadcast(Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(file)))
MediaScannerConnection.scanFile(context, new String[]{file.getAbsolutePath()}, null, null); MediaScannerConnection.scanFile(context, arrayOf(file.absolutePath), null, null)
final Uri uri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", file); val uri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", file)
final ContentResolver contentResolver = context.getContentResolver(); val contentResolver = context.contentResolver
final Bitmap bitmap = getThumbnail(context, file, uri, contentResolver); val bitmap = getThumbnail(context, file, uri, contentResolver)
final String downloadComplete = context.getString(R.string.downloader_complete); val downloadComplete = context.getString(R.string.downloader_complete)
final Intent intent = new Intent(Intent.ACTION_VIEW, uri) val intent = Intent(Intent.ACTION_VIEW, uri)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_FROM_BACKGROUND or Intent.FLAG_FROM_BACKGROUND
| Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION) or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
.putExtra(Intent.EXTRA_STREAM, uri); .putExtra(Intent.EXTRA_STREAM, uri)
final PendingIntent pendingIntent = PendingIntent.getActivity( val pendingIntent = PendingIntent.getActivity(
context, context,
DOWNLOAD_NOTIFICATION_INTENT_REQUEST_CODE, DOWNLOAD_NOTIFICATION_INTENT_REQUEST_CODE,
intent, intent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_ONE_SHOT PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_ONE_SHOT
); )
final int notificationId = getNotificationId() + count; val notificationId = notificationId + count
notificationIds.add(notificationId); notificationIds.add(notificationId)
count++; count++
final NotificationCompat.Builder builder = new NotificationCompat.Builder(context, DOWNLOAD_CHANNEL_ID) val builder: NotificationCompat.Builder = NotificationCompat.Builder(context, DOWNLOAD_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_download) .setSmallIcon(R.drawable.ic_download)
.setContentText(null) .setContentText(null)
.setContentTitle(downloadComplete) .setContentTitle(downloadComplete)
.setWhen(System.currentTimeMillis()) .setWhen(System.currentTimeMillis())
.setOnlyAlertOnce(true) .setOnlyAlertOnce(true)
.setAutoCancel(true) .setAutoCancel(true)
.setGroup(NOTIF_GROUP_NAME + "_" + getId()) .setGroup(NOTIF_GROUP_NAME + "_" + id)
.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY) .setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY)
.setContentIntent(pendingIntent) .setContentIntent(pendingIntent)
.addAction(R.drawable.ic_delete, .addAction(R.drawable.ic_delete,
context.getString(R.string.delete), context.getString(R.string.delete),
DeleteImageIntentService.pendingIntent(context, filePath, notificationId)); DeleteImageIntentService.pendingIntent(context, filePath, notificationId))
if (bitmap != null) { if (bitmap != null) {
builder.setLargeIcon(bitmap) builder.setLargeIcon(bitmap)
.setStyle(new NotificationCompat.BigPictureStyle() .setStyle(NotificationCompat.BigPictureStyle()
.bigPicture(bitmap) .bigPicture(bitmap)
.bigLargeIcon(null)) .bigLargeIcon(null))
.setBadgeIconType(NotificationCompat.BADGE_ICON_SMALL); .setBadgeIconType(NotificationCompat.BADGE_ICON_SMALL)
} }
notifications.add(builder); notifications.add(builder)
} }
Notification summaryNotification = null; var summaryNotification: Notification? = null
if (urlToFilePathMap.size() != 1) { if (urlToFilePathMap.size != 1) {
final String text = "Downloaded " + urlToFilePathMap.size() + " items"; val text = "Downloaded " + urlToFilePathMap.size + " items"
summaryNotification = new NotificationCompat.Builder(context, DOWNLOAD_CHANNEL_ID) summaryNotification = NotificationCompat.Builder(context, DOWNLOAD_CHANNEL_ID)
.setContentTitle("Downloaded") .setContentTitle("Downloaded")
.setContentText(text) .setContentText(text)
.setSmallIcon(R.drawable.ic_download) .setSmallIcon(R.drawable.ic_download)
.setStyle(new NotificationCompat.InboxStyle().setSummaryText(text)) .setStyle(NotificationCompat.InboxStyle().setSummaryText(text))
.setGroup(NOTIF_GROUP_NAME + "_" + getId()) .setGroup(NOTIF_GROUP_NAME + "_" + id)
.setGroupSummary(true) .setGroupSummary(true)
.build(); .build()
} }
for (int i = 0; i < notifications.size(); i++) { for (i in notifications.indices) {
final NotificationCompat.Builder builder = notifications.get(i); val builder = notifications[i]
// only make sound and vibrate for the last notification // only make sound and vibrate for the last notification
if (i != notifications.size() - 1) { if (i != notifications.size - 1) {
builder.setSound(null) builder.setSound(null)
.setVibrate(null); .setVibrate(null)
} }
notificationManager.notify(notificationIds.get(i), builder.build()); notificationManager.notify(notificationIds[i], builder.build())
} }
if (summaryNotification != null) { if (summaryNotification != null) {
notificationManager.notify(getNotificationId() + count, summaryNotification); notificationManager.notify(notificationId + count, summaryNotification)
} }
} }
@Nullable private fun getThumbnail(
private Bitmap getThumbnail(final Context context, context: Context,
final File file, file: File,
final Uri uri, uri: Uri,
final ContentResolver contentResolver) { contentResolver: ContentResolver,
final String mimeType = Utils.getMimeType(uri, contentResolver); ): Bitmap? {
if (TextUtils.isEmpty(mimeType)) return null; val mimeType = Utils.getMimeType(uri, contentResolver)
Bitmap bitmap = null; if (isEmpty(mimeType)) return null
var bitmap: Bitmap? = null
if (mimeType.startsWith("image")) { if (mimeType.startsWith("image")) {
try { try {
final BitmapUtils.BitmapResult bitmapResult = BitmapUtils val bitmapResult = BitmapUtils.getBitmapResult(
.getBitmapResult(context.getContentResolver(), uri, THUMBNAIL_SIZE, THUMBNAIL_SIZE, -1, true); context.contentResolver,
if (bitmapResult == null) return null; uri,
bitmap = bitmapResult.bitmap; BitmapUtils.THUMBNAIL_SIZE,
} catch (final Exception e) { BitmapUtils.THUMBNAIL_SIZE,
Log.e(TAG, "", e); -1f,
true
) ?: return null
bitmap = bitmapResult.bitmap
} catch (e: Exception) {
Log.e(TAG, "", e)
} }
return bitmap; return bitmap
} }
if (mimeType.startsWith("video")) { if (mimeType.startsWith("video")) {
try { try {
MediaMetadataRetriever retriever = new MediaMetadataRetriever(); val retriever = MediaMetadataRetriever()
try { bitmap = try {
try { try {
retriever.setDataSource(context, uri); retriever.setDataSource(context, uri)
} catch (final Exception e) { } catch (e: Exception) {
retriever.setDataSource(file.getAbsolutePath()); retriever.setDataSource(file.absolutePath)
} }
bitmap = retriever.getFrameAtTime(); retriever.frameAtTime
} finally { } finally {
try { try {
retriever.release(); retriever.release()
} catch (Exception e) { } catch (e: Exception) {
Log.e(TAG, "getThumbnail: ", e); Log.e(TAG, "getThumbnail: ", e)
} }
} }
} catch (final Exception e) { } catch (e: Exception) {
Log.e(TAG, "", e); Log.e(TAG, "", e)
} }
} }
return bitmap; return bitmap
} }
public static class DownloadRequest { class DownloadRequest private constructor(val urlToFilePathMap: Map<String, String>) {
private final Map<String, String> urlToFilePathMap;
public static class Builder { class Builder {
private Map<String, String> urlToFilePathMap; private var urlToFilePathMap: MutableMap<String, String> = mutableMapOf()
fun setUrlToFilePathMap(urlToFilePathMap: MutableMap<String, String>): Builder {
public Builder setUrlToFilePathMap(final Map<String, String> urlToFilePathMap) { this.urlToFilePathMap = urlToFilePathMap
this.urlToFilePathMap = urlToFilePathMap; return this
return this;
} }
public Builder addUrl(@NonNull final String url, @NonNull final String filePath) { fun addUrl(url: String, filePath: String): Builder {
if (urlToFilePathMap == null) { urlToFilePathMap[url] = filePath
urlToFilePathMap = new HashMap<>(); return this
}
urlToFilePathMap.put(url, filePath);
return this;
} }
public DownloadRequest build() { fun build(): DownloadRequest {
return new DownloadRequest(urlToFilePathMap); return DownloadRequest(urlToFilePathMap)
} }
} }
public static Builder builder() { companion object {
return new Builder(); @JvmStatic
} fun builder(): Builder {
return Builder()
private DownloadRequest(final Map<String, String> urlToFilePathMap) { }
this.urlToFilePathMap = urlToFilePathMap;
}
public Map<String, String> getUrlToFilePathMap() {
return urlToFilePathMap;
} }
} }
}
companion object {
const val PROGRESS = "PROGRESS"
const val URL = "URL"
const val KEY_DOWNLOAD_REQUEST_JSON = "download_request_json"
private const val DOWNLOAD_GROUP = "DOWNLOAD_GROUP"
private const val DOWNLOAD_NOTIFICATION_INTENT_REQUEST_CODE = 2020
private const val DELETE_IMAGE_REQUEST_CODE = 2030
}
}