@@ -268,7 +268,8 @@ public class FileBackend {
return inSampleSize;
}
- private static Dimensions getVideoDimensions(Context context, Uri uri) throws NotAVideoFile, IOException {
+ private static Dimensions getVideoDimensions(Context context, Uri uri)
+ throws NotAVideoFile, IOException {
MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever();
try {
mediaMetadataRetriever.setDataSource(context, uri);
@@ -663,16 +664,14 @@ public class FileBackend {
}
}
- private void copyFileToPrivateStorage(File file, Uri uri) throws FileCopyException {
+ private void copyFileToPrivateStorage(final File file, final Uri uri) throws FileCopyException {
final var parentDirectory = file.getParentFile();
if (parentDirectory != null && parentDirectory.mkdirs()) {
- Log.d(Config.LOGTAG,"created directory "+parentDirectory.getAbsolutePath());
+ Log.d(Config.LOGTAG, "created directory " + parentDirectory.getAbsolutePath());
}
try {
if (file.createNewFile()) {
- Log.d(
- Config.LOGTAG,
- "copy file (" + uri.toString() + ") to private storage " + file.getAbsolutePath());
+ Log.d(Config.LOGTAG, "created empty file " + file.getAbsolutePath());
}
} catch (final IOException e) {
throw new FileCopyException(R.string.error_unable_to_create_temporary_file);
@@ -708,9 +707,10 @@ public class FileBackend {
}
}
- public void copyFileToPrivateStorage(Message message, Uri uri, String type)
+ public void copyFileToPrivateStorage(final Message message, final Uri uri, final String type)
throws FileCopyException {
- final String mime = MimeUtils.guessMimeTypeFromUriAndMime(mXmppConnectionService, uri, type);
+ final String mime =
+ MimeUtils.guessMimeTypeFromUriAndMime(mXmppConnectionService, uri, type);
Log.d(Config.LOGTAG, "copy " + uri.toString() + " to private storage (mime=" + mime + ")");
String extension = MimeUtils.guessExtensionFromMimeType(mime);
if (extension == null) {
@@ -1500,7 +1500,7 @@ public class FileBackend {
return calcSampleSize(options, size);
}
- public void updateFileParams(Message message) {
+ public void updateFileParams(final Message message) {
updateFileParams(message, null);
}
@@ -11,12 +11,6 @@ import androidx.annotation.NonNull;
import com.otaliastudios.transcoder.Transcoder;
import com.otaliastudios.transcoder.TranscoderListener;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.util.Objects;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.PgpEngine;
@@ -27,6 +21,12 @@ import eu.siacs.conversations.ui.UiCallback;
import eu.siacs.conversations.utils.MimeUtils;
import eu.siacs.conversations.utils.TranscoderStrategies;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.Objects;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
public class AttachFileToConversationRunnable implements Runnable, TranscoderListener {
private final XmppConnectionService mXmppConnectionService;
@@ -38,16 +38,26 @@ public class AttachFileToConversationRunnable implements Runnable, TranscoderLis
private final long originalFileSize;
private int currentProgress = -1;
- AttachFileToConversationRunnable(XmppConnectionService xmppConnectionService, Uri uri, String type, Message message, UiCallback<Message> callback) {
+ AttachFileToConversationRunnable(
+ XmppConnectionService xmppConnectionService,
+ Uri uri,
+ String type,
+ Message message,
+ UiCallback<Message> callback) {
this.uri = uri;
this.type = type;
this.mXmppConnectionService = xmppConnectionService;
this.message = message;
this.callback = callback;
- final String mimeType = MimeUtils.guessMimeTypeFromUriAndMime(mXmppConnectionService, uri, type);
- final int autoAcceptFileSize = mXmppConnectionService.getResources().getInteger(R.integer.auto_accept_filesize);
+ final String mimeType =
+ MimeUtils.guessMimeTypeFromUriAndMime(mXmppConnectionService, uri, type);
+ final int autoAcceptFileSize =
+ mXmppConnectionService.getResources().getInteger(R.integer.auto_accept_filesize);
this.originalFileSize = FileBackend.getFileSize(mXmppConnectionService, uri);
- this.isVideoMessage = (mimeType != null && mimeType.startsWith("video/")) && originalFileSize > autoAcceptFileSize && !"uncompressed".equals(getVideoCompression());
+ this.isVideoMessage =
+ (mimeType != null && mimeType.startsWith("video/"))
+ && originalFileSize > autoAcceptFileSize
+ && !"uncompressed".equals(getVideoCompression());
}
boolean isVideoMessage() {
@@ -67,7 +77,9 @@ public class AttachFileToConversationRunnable implements Runnable, TranscoderLis
}
} else {
try {
- mXmppConnectionService.getFileBackend().copyFileToPrivateStorage(message, uri, type);
+ mXmppConnectionService
+ .getFileBackend()
+ .copyFileToPrivateStorage(message, uri, type);
mXmppConnectionService.getFileBackend().updateFileParams(message);
if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) {
final PgpEngine pgpEngine = mXmppConnectionService.getPgpEngine();
@@ -80,16 +92,26 @@ public class AttachFileToConversationRunnable implements Runnable, TranscoderLis
mXmppConnectionService.sendMessage(message);
callback.success(message);
}
- } catch (FileBackend.FileCopyException e) {
+ } catch (final FileBackend.FileCopyException e) {
callback.error(e.getResId(), message);
}
}
}
+ private void fallbackToProcessAsFile() {
+ final var file = mXmppConnectionService.getFileBackend().getFile(message);
+ if (file.exists() && file.delete()) {
+ Log.d(Config.LOGTAG, "deleted preexisting file " + file.getAbsolutePath());
+ }
+ XmppConnectionService.FILE_ATTACHMENT_EXECUTOR.execute(this::processAsFile);
+ }
+
private void processAsVideo() throws FileNotFoundException {
Log.d(Config.LOGTAG, "processing file as video");
mXmppConnectionService.startOngoingVideoTranscodingForegroundNotification();
- mXmppConnectionService.getFileBackend().setupRelativeFilePath(message, String.format("%s.%s", message.getUuid(), "mp4"));
+ mXmppConnectionService
+ .getFileBackend()
+ .setupRelativeFilePath(message, String.format("%s.%s", message.getUuid(), "mp4"));
final DownloadableFile file = mXmppConnectionService.getFileBackend().getFile(message);
if (Objects.requireNonNull(file.getParentFile()).mkdirs()) {
Log.d(Config.LOGTAG, "created parent directory for video file");
@@ -99,16 +121,23 @@ public class AttachFileToConversationRunnable implements Runnable, TranscoderLis
final Future<Void> future;
try {
- future = Transcoder.into(file.getAbsolutePath()).
- addDataSource(mXmppConnectionService, uri)
- .setVideoTrackStrategy(highQuality ? TranscoderStrategies.VIDEO_720P : TranscoderStrategies.VIDEO_360P)
- .setAudioTrackStrategy(highQuality ? TranscoderStrategies.AUDIO_HQ : TranscoderStrategies.AUDIO_MQ)
- .setListener(this)
- .transcode();
+ future =
+ Transcoder.into(file.getAbsolutePath())
+ .addDataSource(mXmppConnectionService, uri)
+ .setVideoTrackStrategy(
+ highQuality
+ ? TranscoderStrategies.VIDEO_720P
+ : TranscoderStrategies.VIDEO_360P)
+ .setAudioTrackStrategy(
+ highQuality
+ ? TranscoderStrategies.AUDIO_HQ
+ : TranscoderStrategies.AUDIO_MQ)
+ .setListener(this)
+ .transcode();
} catch (final RuntimeException e) {
// transcode can already throw if there is an invalid file format or a platform bug
mXmppConnectionService.stopOngoingVideoTranscodingForegroundNotification();
- processAsFile();
+ fallbackToProcessAsFile();
return;
}
try {
@@ -118,9 +147,9 @@ public class AttachFileToConversationRunnable implements Runnable, TranscoderLis
} catch (final ExecutionException e) {
if (e.getCause() instanceof Error) {
mXmppConnectionService.stopOngoingVideoTranscodingForegroundNotification();
- processAsFile();
+ fallbackToProcessAsFile();
} else {
- Log.d(Config.LOGTAG, "ignoring execution exception. Should get handled by onTranscodeFiled() instead", e);
+ Log.d(Config.LOGTAG, "ignoring execution exception. Handled by onTranscodeFiled()");
}
}
}
@@ -130,7 +159,9 @@ public class AttachFileToConversationRunnable implements Runnable, TranscoderLis
final int p = (int) Math.round(progress * 100);
if (p > currentProgress) {
currentProgress = p;
- mXmppConnectionService.getNotificationService().updateFileAddingNotification(p, message);
+ mXmppConnectionService
+ .getNotificationService()
+ .updateFileAddingNotification(p, message);
}
}
@@ -139,11 +170,15 @@ public class AttachFileToConversationRunnable implements Runnable, TranscoderLis
mXmppConnectionService.stopOngoingVideoTranscodingForegroundNotification();
final File file = mXmppConnectionService.getFileBackend().getFile(message);
long convertedFileSize = mXmppConnectionService.getFileBackend().getFile(message).getSize();
- Log.d(Config.LOGTAG, "originalFileSize=" + originalFileSize + " convertedFileSize=" + convertedFileSize);
+ Log.d(
+ Config.LOGTAG,
+ "originalFileSize=" + originalFileSize + " convertedFileSize=" + convertedFileSize);
if (originalFileSize != 0 && convertedFileSize >= originalFileSize) {
if (file.delete()) {
- Log.d(Config.LOGTAG, "original file size was smaller. deleting and processing as file");
- processAsFile();
+ Log.d(
+ Config.LOGTAG,
+ "original file size was smaller. deleting and processing as file");
+ fallbackToProcessAsFile();
return;
} else {
Log.d(Config.LOGTAG, "unable to delete converted file");
@@ -161,14 +196,14 @@ public class AttachFileToConversationRunnable implements Runnable, TranscoderLis
@Override
public void onTranscodeCanceled() {
mXmppConnectionService.stopOngoingVideoTranscodingForegroundNotification();
- processAsFile();
+ fallbackToProcessAsFile();
}
@Override
public void onTranscodeFailed(@NonNull final Throwable exception) {
mXmppConnectionService.stopOngoingVideoTranscodingForegroundNotification();
Log.d(Config.LOGTAG, "video transcoding failed", exception);
- processAsFile();
+ fallbackToProcessAsFile();
}
@Override
@@ -176,7 +211,7 @@ public class AttachFileToConversationRunnable implements Runnable, TranscoderLis
if (this.isVideoMessage()) {
try {
processAsVideo();
- } catch (FileNotFoundException e) {
+ } catch (final FileNotFoundException e) {
processAsFile();
}
} else {
@@ -189,7 +224,9 @@ public class AttachFileToConversationRunnable implements Runnable, TranscoderLis
}
public static String getVideoCompression(final Context context) {
- final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
- return preferences.getString("video_compression", context.getResources().getString(R.string.video_compression));
+ final SharedPreferences preferences =
+ PreferenceManager.getDefaultSharedPreferences(context);
+ return preferences.getString(
+ "video_compression", context.getResources().getString(R.string.video_compression));
}
}