Added Attachemtns Uri handling after single aattachment download.

MAILAND-1337
This commit is contained in:
Tomasz Giszczak 2021-02-04 12:37:25 +01:00
parent fd40973ac5
commit fd536f2674
7 changed files with 129 additions and 157 deletions

View File

@ -400,7 +400,7 @@ public class AddAttachmentsActivity extends BaseStoragePermissionActivity implem
public void onDownloadAttachmentEvent(DownloadedAttachmentEvent event) {
//once attachment has been downloaded
if (event.getStatus().equals(Status.SUCCESS)) {
DownloadUtils.viewAttachment(this, event.getFilename());
DownloadUtils.viewAttachment(this, event.getFilename(), event.getAttachmentUri());
TextExtensions.showToast(this, String.format(getString(R.string.attachment_download_success), event.getFilename()), Toast.LENGTH_SHORT);
} else {
TextExtensions.showToast(this, String.format(getString(R.string.attachment_download_failed), event.getFilename()), Toast.LENGTH_SHORT);

View File

@ -621,7 +621,7 @@ internal class MessageDetailsActivity :
attachmentsListAdapter.setIsPgpEncrypted(viewModel.isPgpEncrypted())
attachmentsListAdapter.setDownloaded(eventAttachmentId, isDownloaded)
if (isDownloaded) {
DownloadUtils.viewAttachment(this, event.filename)
DownloadUtils.viewAttachment(this, event.filename, event.attachmentUri)
} else {
showToast(R.string.downloading)
}

View File

@ -18,32 +18,33 @@
*/
package ch.protonmail.android.api.models.room.attachmentMetadata
import androidx.room.*
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
/**
* Created by Kamil Rajtar on 14.07.18.
*/
@Dao
abstract class AttachmentMetadataDatabase {
interface AttachmentMetadataDatabase {
@Insert(onConflict=OnConflictStrategy.REPLACE)
abstract fun insertAttachmentMetadata(attachmentMetadata:AttachmentMetadata)
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAttachmentMetadata(attachmentMetadata: AttachmentMetadata)
@Delete
abstract fun deleteAttachmentMetadata(attachmentMetadata:AttachmentMetadata)
@Delete
fun deleteAttachmentMetadata(attachmentMetadata: AttachmentMetadata)
@Query("DELETE FROM $TABLE_ATTACHMENT_METADATA")
abstract fun clearAttachmentMetadataCache()
@Query("DELETE FROM $TABLE_ATTACHMENT_METADATA")
fun clearAttachmentMetadataCache()
@Query("SELECT SUM(${COLUMN_ATTACHMENT_FILE_SIZE}) size FROM $TABLE_ATTACHMENT_METADATA")
abstract fun getAllAttachmentsSizeUsed():Long
@Query("SELECT SUM($COLUMN_ATTACHMENT_FILE_SIZE) size FROM $TABLE_ATTACHMENT_METADATA")
fun getAllAttachmentsSizeUsed(): Long
@Query("SELECT * FROM $TABLE_ATTACHMENT_METADATA WHERE ${COLUMN_ATTACHMENT_FOLDER_LOCATION}=:messageId")
abstract fun getAllAttachmentsForMessage(messageId:String):List<AttachmentMetadata>
@Query("SELECT * FROM $TABLE_ATTACHMENT_METADATA WHERE ${COLUMN_ATTACHMENT_FOLDER_LOCATION}=:messageId")
fun getAllAttachmentsForMessage(messageId: String): List<AttachmentMetadata>
@Query("SELECT * FROM $TABLE_ATTACHMENT_METADATA WHERE ${COLUMN_ATTACHMENT_FOLDER_LOCATION}=:messageId AND ${COLUMN_ATTACHMENT_ID}=:attachmentId")
abstract fun getAttachmentMetadataForMessageAndAttachmentId(messageId: String, attachmentId: String): AttachmentMetadata?
@Query("SELECT * FROM $TABLE_ATTACHMENT_METADATA WHERE ${COLUMN_ATTACHMENT_FOLDER_LOCATION}=:messageId AND ${COLUMN_ATTACHMENT_ID}=:attachmentId")
fun getAttachmentMetadataForMessageAndAttachmentId(messageId: String, attachmentId: String): AttachmentMetadata?
@Query("SELECT * FROM $TABLE_ATTACHMENT_METADATA")
abstract fun getAllAttachmentsMetadata():List<AttachmentMetadata>
@Query("SELECT * FROM $TABLE_ATTACHMENT_METADATA")
fun getAllAttachmentsMetadata(): List<AttachmentMetadata>
}

View File

@ -154,98 +154,56 @@ class DownloadEmbeddedAttachmentsWorker @WorkerInject constructor(
messageId: String
): Result {
val filenameInCache = attachment.fileName?.replace(" ", "_")?.replace("/", ":") ?: ATTACHMENT_UNKNOWN_FILE_NAME
Timber.v("handleSingleAttachment filename:$filenameInCache DirectoryFile:$attachmentsDirectoryFile")
AppUtil.postEventOnUi(
DownloadedAttachmentEvent(
Status.STARTED, filenameInCache, attachment.attachmentId, messageId, false
Status.STARTED, filenameInCache, null, attachment.attachmentId, messageId, false
)
)
download(attachment, filenameInCache, crypto)
// val attachmentFile = File(attachmentsDirectoryFile, filenameInCache)
val attachmentUri = downloadAttachment(attachment, filenameInCache, crypto)
// applicationContext.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)?.let { externalDirectory ->
// val uniqueFilenameInDownloads = downloadHelper.createUniqueFilename(
// attachment.fileName ?: ATTACHMENT_UNKNOWN_FILE_NAME,
// externalDirectory
// )
//
// try {
// val decryptedByteArray = downloadHelper.getAttachmentData(
// crypto,
// attachment.mimeData,
// attachment.attachmentId!!,
// attachment.keyPackets,
// attachment.fileSize,
// uniqueFilenameInDownloads
// )
// FileOutputStream(attachmentFile).use {
// it.write(decryptedByteArray)
// }
//
// val attachmentMetadata = AttachmentMetadata(
// attachment.attachmentId!!,
// attachment.fileName!!,
// attachment.fileSize,
// attachment.messageId + "/" + attachment.attachmentId + "/" + filenameInCache,
// attachment.messageId, System.currentTimeMillis()
// )
// attachmentMetadataDatabase.insertAttachmentMetadata(attachmentMetadata)
//
// attachmentFile.copyTo(
// File(
// externalDirectory,
// uniqueFilenameInDownloads
// )
// )
//
// } catch (e: Exception) {
// Timber.e(e, "handleSingleAttachment exception")
// AppUtil.postEventOnUi(
// DownloadedAttachmentEvent(Status.FAILED, filenameInCache, attachment.attachmentId, messageId, false)
// )
// return Result.failure()
// }
// AppUtil.postEventOnUi(
// DownloadedAttachmentEvent(
// Status.SUCCESS, uniqueFilenameInDownloads, attachment.attachmentId, messageId, false
// )
// )
// } ?: run {
// Timber.w("Unable to access DIRECTORY_DOWNLOADS to save attachments")
// }
AppUtil.postEventOnUi(
DownloadedAttachmentEvent(
Status.SUCCESS, filenameInCache, attachment.attachmentId, messageId, false
if (attachmentUri != null) {
val attachmentMetadata = AttachmentMetadata(
attachment.attachmentId!!,
attachment.fileName!!,
attachment.fileSize,
attachment.messageId + "/" + attachment.attachmentId + "/" + filenameInCache,
attachment.messageId, System.currentTimeMillis()
)
)
attachmentMetadataDatabase.insertAttachmentMetadata(attachmentMetadata)
AppUtil.postEventOnUi(
DownloadedAttachmentEvent(
Status.SUCCESS, filenameInCache, attachmentUri, attachment.attachmentId, messageId, false
)
)
} else {
Timber.w("handleSingleAttachment failure")
AppUtil.postEventOnUi(
DownloadedAttachmentEvent(
Status.FAILED, filenameInCache, null, attachment.attachmentId, messageId, false
)
)
return Result.failure()
}
AttachmentClearingService.startRegularClearUpService() // TODO don't call it every time we download attachments
return Result.success()
}
suspend fun download(attachment: Attachment, filename: String, crypto: AddressCrypto) {
private suspend fun downloadAttachment(attachment: Attachment, filename: String, crypto: AddressCrypto): Uri? =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
downloadQ(attachment, filename, crypto)
downloadAttachmentForAndroidQ(attachment, filename, crypto)
} else {
downloadLegacy(attachment, filename, crypto)
downloadAttachmentBeforeQ(attachment, filename, crypto)
}
val attachmentMetadata = AttachmentMetadata(
attachment.attachmentId!!,
attachment.fileName!!,
attachment.fileSize,
attachment.messageId + "/" + attachment.attachmentId + "/" + filename,
attachment.messageId, System.currentTimeMillis()
)
attachmentMetadataDatabase.insertAttachmentMetadata(attachmentMetadata)
}
@TargetApi(Build.VERSION_CODES.Q)
private suspend fun downloadQ(
private suspend fun downloadAttachmentForAndroidQ(
attachment: Attachment,
filename: String,
crypto: AddressCrypto
@ -287,7 +245,7 @@ class DownloadEmbeddedAttachmentsWorker @WorkerInject constructor(
return@withContext uri
}
private suspend fun downloadLegacy(
private suspend fun downloadAttachmentBeforeQ(
attachment: Attachment,
filename: String,
crypto: AddressCrypto

View File

@ -411,7 +411,7 @@ public class ProtonMailApplication extends Application implements androidx.work.
public void onDownloadAttachmentEvent(DownloadedAttachmentEvent event) {
final Status status = event.getStatus();
if (status != Status.FAILED) {
DownloadUtils.viewAttachment(this, event.getFilename(), !event.isOfflineLoaded());
DownloadUtils.viewAttachment(this, event.getFilename(), event.getAttachmentUri(), !event.isOfflineLoaded());
}
}

View File

@ -19,17 +19,31 @@
package ch.protonmail.android.events;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class DownloadedAttachmentEvent {
private final Status status;
private final String filename;
private final Uri attachmentUri;
private final String attachmentId;
private final String messageId;
private final boolean offlineLoaded;
public DownloadedAttachmentEvent(Status status, String filename, String attachmentId, String messageId, boolean offlineLoaded){
public DownloadedAttachmentEvent(
Status status,
@NonNull String filename,
@Nullable Uri attachmentUri,
String attachmentId,
String messageId,
boolean offlineLoaded
){
this.status = status;
this.filename = filename;
this.attachmentUri = attachmentUri;
this.attachmentId = attachmentId;
this.messageId = messageId;
this.offlineLoaded = offlineLoaded;
@ -39,10 +53,16 @@ public class DownloadedAttachmentEvent {
return status;
}
@NonNull
public String getFilename(){
return filename;
}
@Nullable
public Uri getAttachmentUri(){
return attachmentUri;
}
public String getAttachmentId() {
return attachmentId;
}

View File

@ -1,18 +1,18 @@
/*
* Copyright (c) 2020 Proton Technologies AG
*
*
* This file is part of ProtonMail.
*
*
* ProtonMail 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.
*
*
* ProtonMail 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 ProtonMail. If not, see https://www.gnu.org/licenses/.
*/
@ -25,10 +25,10 @@ import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Environment;
import android.text.TextUtils;
import android.webkit.MimeTypeMap;
import androidx.annotation.Nullable;
import androidx.core.content.FileProvider;
import java.io.File;
@ -40,68 +40,61 @@ import timber.log.Timber;
public class DownloadUtils {
public static void viewAttachment(Context context, String filename) {
String ext = filename.substring(filename.lastIndexOf(".") + 1);
filename = filename.replace(filename.substring(filename.lastIndexOf(".") + 1), ext.toLowerCase());
File file = new File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS) + Constants.DIR_ATTACHMENT_DOWNLOADS, filename);
Uri uri = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".provider", file);
String mimeType = "";
final ContentResolver resolver = context.getContentResolver();
public static void viewAttachment(Context context, String filename, @Nullable Uri uri) {
if (uri != null) {
String mimeType = "";
final ContentResolver resolver = context.getContentResolver();
if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
mimeType = resolver.getType(uri);
Cursor cursor = resolver.query(uri, null, null, null, null);
cursor.close();
} else if (ContentResolver.SCHEME_FILE.equals(uri.getScheme())) {
String extension = MimeTypeMap.getFileExtensionFromUrl(filename);
mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.toLowerCase());
if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
mimeType = resolver.getType(uri);
Cursor cursor = resolver.query(uri, null, null, null, null);
cursor.close();
} else if (ContentResolver.SCHEME_FILE.equals(uri.getScheme())) {
String extension = MimeTypeMap.getFileExtensionFromUrl(file.getName());
mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.toLowerCase());
if (mimeType == null) {
mimeType = Constants.MIME_TYPE_UNKNOWN_FILE;
if (mimeType == null) {
mimeType = Constants.MIME_TYPE_UNKNOWN_FILE;
}
}
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setType(mimeType);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(uri, mimeType);
try {
context.startActivity(intent);
} catch (ActivityNotFoundException notFoundException) {
Timber.i(notFoundException, "Unable to view attachment");
}
}
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setType(mimeType);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(uri, mimeType);
try {
context.startActivity(intent);
} catch (ActivityNotFoundException e) {
Timber.i(e);
}
}
public static void viewAttachment(Context context, String filename, boolean showNotification) {
String ext = filename.substring(filename.lastIndexOf(".") + 1);
filename = filename.replace(filename.substring(filename.lastIndexOf(".") + 1), ext.toLowerCase());
File file = new File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS) + Constants.DIR_ATTACHMENT_DOWNLOADS, filename);
Uri uri = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".provider", file);
String mimeType = "";
final ContentResolver resolver = context.getContentResolver();
public static void viewAttachment(Context context, String fileName, @Nullable Uri uri, boolean showNotification) {
if (uri != null) {
String mimeType = "";
final ContentResolver resolver = context.getContentResolver();
if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
mimeType = resolver.getType(uri);
Cursor cursor = resolver.query(uri, null, null, null, null);
cursor.close();
} else if (ContentResolver.SCHEME_FILE.equals(uri.getScheme())) {
String extension = fileName.substring(fileName.lastIndexOf(".") + 1);
if (!TextUtils.isEmpty(extension)) {
extension = extension.toLowerCase();
}
mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.toLowerCase());
if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
mimeType = resolver.getType(uri);
Cursor cursor = resolver.query(uri, null, null, null, null);
cursor.close();
} else if (ContentResolver.SCHEME_FILE.equals(uri.getScheme())) {
String fileName = file.getName();
String extension = fileName.substring(fileName.lastIndexOf(".") + 1);
if (!TextUtils.isEmpty(extension)) {
extension = extension.toLowerCase();
if (mimeType == null) {
mimeType = Constants.MIME_TYPE_UNKNOWN_FILE;
}
}
mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.toLowerCase());
if (mimeType == null) {
mimeType = Constants.MIME_TYPE_UNKNOWN_FILE;
}
NotificationManager notifyManager = (NotificationManager) context.getSystemService(
Context.NOTIFICATION_SERVICE);
INotificationServer notificationServer = new NotificationServer(context, notifyManager);
notificationServer.notifyAboutAttachment(fileName, uri, mimeType, showNotification);
}
NotificationManager notifyManager = (NotificationManager) context.getSystemService(
Context.NOTIFICATION_SERVICE);
INotificationServer notificationServer = new NotificationServer(context, notifyManager);
notificationServer.notifyAboutAttachment(filename, uri, mimeType, showNotification);
}
public static void viewCachedAttachmentFile(Context context, String filename, String localLocation) {
@ -132,8 +125,8 @@ public class DownloadUtils {
try {
context.startActivity(intent);
} catch (ActivityNotFoundException e) {
Timber.i(e);
} catch (ActivityNotFoundException notFoundException) {
Timber.i(notFoundException, "Unable to view the file");
}
}
}