1package eu.siacs.conversations.services;
2
3import android.net.Uri;
4import android.os.Build;
5import android.os.ParcelFileDescriptor;
6import android.util.Log;
7
8import net.ypresto.androidtranscoder.MediaTranscoder;
9import net.ypresto.androidtranscoder.format.MediaFormatStrategy;
10import net.ypresto.androidtranscoder.format.MediaFormatStrategyPresets;
11
12import java.io.FileDescriptor;
13import java.io.FileNotFoundException;
14import java.util.concurrent.atomic.AtomicInteger;
15
16import eu.siacs.conversations.Config;
17import eu.siacs.conversations.R;
18import eu.siacs.conversations.crypto.PgpEngine;
19import eu.siacs.conversations.entities.DownloadableFile;
20import eu.siacs.conversations.entities.Message;
21import eu.siacs.conversations.persistance.FileBackend;
22import eu.siacs.conversations.ui.UiCallback;
23import eu.siacs.conversations.utils.MimeUtils;
24
25public class AttachFileToConversationRunnable implements Runnable, MediaTranscoder.Listener {
26
27 private final XmppConnectionService mXmppConnectionService;
28 private final Message message;
29 private final Uri uri;
30 private final UiCallback<Message> callback;
31 private final boolean isVideoMessage;
32 private int currentProgress = -1;
33
34 public AttachFileToConversationRunnable(XmppConnectionService xmppConnectionService, Uri uri, Message message, UiCallback<Message> callback) {
35 this.uri = uri;
36 this.mXmppConnectionService = xmppConnectionService;
37 this.message = message;
38 this.callback = callback;
39 final String mimeType = MimeUtils.guessMimeTypeFromUri(mXmppConnectionService, uri);
40 this.isVideoMessage = (mimeType != null && mimeType.startsWith("video/") && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2);
41 }
42
43
44 private void processAsFile() {
45 final String path = mXmppConnectionService.getFileBackend().getOriginalPath(uri);
46 if (path != null) {
47 message.setRelativeFilePath(path);
48 mXmppConnectionService.getFileBackend().updateFileParams(message);
49 if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) {
50 mXmppConnectionService.getPgpEngine().encrypt(message, callback);
51 } else {
52 callback.success(message);
53 }
54 } else {
55 try {
56 mXmppConnectionService.getFileBackend().copyFileToPrivateStorage(message, uri);
57 mXmppConnectionService.getFileBackend().updateFileParams(message);
58 if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) {
59 final PgpEngine pgpEngine = mXmppConnectionService.getPgpEngine();
60 if (pgpEngine != null) {
61 pgpEngine.encrypt(message, callback);
62 } else if (callback != null) {
63 callback.error(R.string.unable_to_connect_to_keychain, null);
64 }
65 } else {
66 callback.success(message);
67 }
68 } catch (FileBackend.FileCopyException e) {
69 callback.error(e.getResId(), message);
70 }
71 }
72 }
73
74 private void processAsVideo() throws FileNotFoundException {
75 Log.d(Config.LOGTAG,"processing file as video");
76 mXmppConnectionService.startForcingForegroundNotification();
77 message.setRelativeFilePath(message.getUuid() + ".mp4");
78 final DownloadableFile file = mXmppConnectionService.getFileBackend().getFile(message);
79 final int runtime = mXmppConnectionService.getFileBackend().getMediaRuntime(uri);
80 MediaFormatStrategy formatStrategy = runtime >= 8000 ? MediaFormatStrategyPresets.createExportPreset960x540Strategy() : MediaFormatStrategyPresets.createAndroid720pStrategy();
81 Log.d(Config.LOGTAG,"runtime "+runtime);
82 file.getParentFile().mkdirs();
83 ParcelFileDescriptor parcelFileDescriptor = mXmppConnectionService.getContentResolver().openFileDescriptor(uri, "r");
84 FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
85 MediaTranscoder.getInstance().transcodeVideo(fileDescriptor, file.getAbsolutePath(), formatStrategy, this);
86 }
87
88 @Override
89 public void onTranscodeProgress(double progress) {
90 final int p = (int) Math.round(progress * 100);
91 if (p > currentProgress) {
92 currentProgress = p;
93 mXmppConnectionService.getNotificationService().updateFileAddingNotification(p,message);
94 }
95 }
96
97 @Override
98 public void onTranscodeCompleted() {
99 mXmppConnectionService.stopForcingForegroundNotification();
100 mXmppConnectionService.getFileBackend().updateFileParams(message);
101 if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) {
102 mXmppConnectionService.getPgpEngine().encrypt(message, callback);
103 } else {
104 callback.success(message);
105 }
106 }
107
108 @Override
109 public void onTranscodeCanceled() {
110 mXmppConnectionService.stopForcingForegroundNotification();
111 processAsFile();
112 }
113
114 @Override
115 public void onTranscodeFailed(Exception e) {
116 mXmppConnectionService.stopForcingForegroundNotification();
117 Log.d(Config.LOGTAG,"video transcoding failed "+e.getMessage());
118 processAsFile();
119 }
120
121 @Override
122 public void run() {
123 if (isVideoMessage) {
124 try {
125 processAsVideo();
126 } catch (Throwable e) {
127 processAsFile();
128 }
129 } else {
130 processAsFile();
131 }
132 }
133
134}