AttachFileToConversationRunnable.java

  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.File;
 13import java.io.FileDescriptor;
 14import java.io.FileNotFoundException;
 15import java.util.concurrent.ExecutionException;
 16import java.util.concurrent.Future;
 17import java.util.concurrent.atomic.AtomicInteger;
 18
 19import eu.siacs.conversations.Config;
 20import eu.siacs.conversations.R;
 21import eu.siacs.conversations.crypto.PgpEngine;
 22import eu.siacs.conversations.entities.DownloadableFile;
 23import eu.siacs.conversations.entities.Message;
 24import eu.siacs.conversations.persistance.FileBackend;
 25import eu.siacs.conversations.ui.UiCallback;
 26import eu.siacs.conversations.utils.Android360pFormatStrategy;
 27import eu.siacs.conversations.utils.Android720pFormatStrategy;
 28import eu.siacs.conversations.utils.Android1080pFormatStrategy;
 29import eu.siacs.conversations.utils.MimeUtils;
 30
 31public class AttachFileToConversationRunnable implements Runnable, MediaTranscoder.Listener {
 32
 33	private final XmppConnectionService mXmppConnectionService;
 34	private final Message message;
 35	private final Uri uri;
 36	private final String type;
 37	private final UiCallback<Message> callback;
 38	private final boolean isVideoMessage;
 39	private final long originalFileSize;
 40	private int currentProgress = -1;
 41
 42	public AttachFileToConversationRunnable(XmppConnectionService xmppConnectionService, Uri uri, String type, Message message, UiCallback<Message> callback) {
 43		this.uri = uri;
 44		this.type = type;
 45		this.mXmppConnectionService = xmppConnectionService;
 46		this.message = message;
 47		this.callback = callback;
 48		final String mimeType = type != null ? type : MimeUtils.guessMimeTypeFromUri(mXmppConnectionService, uri);
 49		final int autoAcceptFileSize = mXmppConnectionService.getResources().getInteger(R.integer.auto_accept_filesize);
 50		this.originalFileSize = FileBackend.getFileSize(mXmppConnectionService,uri);
 51		this.isVideoMessage = (mimeType != null && mimeType.startsWith("video/")) && originalFileSize > autoAcceptFileSize;
 52	}
 53
 54	public boolean isVideoMessage() {
 55		return this.isVideoMessage;
 56	}
 57
 58	private void processAsFile() {
 59		final String path = mXmppConnectionService.getFileBackend().getOriginalPath(uri);
 60		if (path != null && !FileBackend.isPathBlacklisted(path)) {
 61			message.setRelativeFilePath(path);
 62			mXmppConnectionService.getFileBackend().updateFileParams(message);
 63			if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) {
 64				mXmppConnectionService.getPgpEngine().encrypt(message, callback);
 65			} else {
 66				mXmppConnectionService.sendMessage(message);
 67				callback.success(message);
 68			}
 69		} else {
 70			try {
 71				mXmppConnectionService.getFileBackend().copyFileToPrivateStorage(message, uri, type);
 72				mXmppConnectionService.getFileBackend().updateFileParams(message);
 73				if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) {
 74					final PgpEngine pgpEngine = mXmppConnectionService.getPgpEngine();
 75					if (pgpEngine != null) {
 76						pgpEngine.encrypt(message, callback);
 77					} else if (callback != null) {
 78						callback.error(R.string.unable_to_connect_to_keychain, null);
 79					}
 80				} else {
 81					mXmppConnectionService.sendMessage(message);
 82					callback.success(message);
 83				}
 84			} catch (FileBackend.FileCopyException e) {
 85				callback.error(e.getResId(), message);
 86			}
 87		}
 88	}
 89
 90	private void processAsVideo() throws FileNotFoundException {
 91		Log.d(Config.LOGTAG,"processing file as video");
 92		mXmppConnectionService.startForcingForegroundNotification();
 93		message.setRelativeFilePath(message.getUuid() + ".mp4");
 94		final DownloadableFile file = mXmppConnectionService.getFileBackend().getFile(message);
 95		final MediaFormatStrategy formatStrategy;
 96		final String compressVideo = mXmppConnectionService.getResources().getString(R.string.video_compression);
 97                    switch (compressVideo) {
 98                            case "720":
 99                                formatStrategy = new Android720pFormatStrategy();
100								Log.d(Config.LOGTAG,"WOOOMP 720 dar " + compressVideo);
101                                break;
102                            case "1080":
103                                formatStrategy = new Android1080pFormatStrategy();
104								Log.d(Config.LOGTAG,"WOOOMP 1080 dar " + compressVideo);
105                                break;
106                            default:
107                                formatStrategy = new Android360pFormatStrategy();
108								Log.d(Config.LOGTAG,"WOOOMP 360 dar" + compressVideo);
109                                break;
110                    } 
111		file.getParentFile().mkdirs();
112		final ParcelFileDescriptor parcelFileDescriptor = mXmppConnectionService.getContentResolver().openFileDescriptor(uri, "r");
113		if (parcelFileDescriptor == null) {
114			throw new FileNotFoundException("Parcel File Descriptor was null");
115		}
116		FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
117		Future<Void> future = MediaTranscoder.getInstance().transcodeVideo(fileDescriptor, file.getAbsolutePath(), formatStrategy, this);
118		try {
119			future.get();
120		} catch (InterruptedException e) {
121			throw new AssertionError(e);
122		} catch (ExecutionException e) {
123			Log.d(Config.LOGTAG,"ignoring execution exception. Should get handled by onTranscodeFiled() instead",e);
124		}
125	}
126
127	@Override
128	public void onTranscodeProgress(double progress) {
129		final int p = (int) Math.round(progress * 100);
130		if (p > currentProgress) {
131			currentProgress = p;
132			mXmppConnectionService.getNotificationService().updateFileAddingNotification(p,message);
133		}
134	}
135
136	@Override
137	public void onTranscodeCompleted() {
138		mXmppConnectionService.stopForcingForegroundNotification();
139		final File file = mXmppConnectionService.getFileBackend().getFile(message);
140		long convertedFileSize = mXmppConnectionService.getFileBackend().getFile(message).getSize();
141		Log.d(Config.LOGTAG,"originalFileSize="+originalFileSize+" convertedFileSize="+convertedFileSize);
142		if (originalFileSize != 0 && convertedFileSize >= originalFileSize) {
143			if (file.delete()) {
144				Log.d(Config.LOGTAG,"original file size was smaller. deleting and processing as file");
145				processAsFile();
146				return;
147			} else {
148				Log.d(Config.LOGTAG,"unable to delete converted file");
149			}
150		}
151		mXmppConnectionService.getFileBackend().updateFileParams(message);
152		if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) {
153			mXmppConnectionService.getPgpEngine().encrypt(message, callback);
154		} else {
155			mXmppConnectionService.sendMessage(message);
156			callback.success(message);
157		}
158	}
159
160	@Override
161	public void onTranscodeCanceled() {
162		mXmppConnectionService.stopForcingForegroundNotification();
163		processAsFile();
164	}
165
166	@Override
167	public void onTranscodeFailed(Exception e) {
168		mXmppConnectionService.stopForcingForegroundNotification();
169		Log.d(Config.LOGTAG,"video transcoding failed",e);
170		processAsFile();
171	}
172
173	@Override
174	public void run() {
175		if (isVideoMessage) {
176			try {
177				processAsVideo();
178			} catch (FileNotFoundException e) {
179				processAsFile();
180			}
181		} else {
182			processAsFile();
183		}
184	}
185
186}