From c0c9ce588ec60f09d0199c53a1229b722e9fa910 Mon Sep 17 00:00:00 2001 From: Christian Schneppe Date: Mon, 18 Sep 2017 21:00:00 +0200 Subject: show permanent notification while transcoding video --- .../pixart/messenger/persistance/FileBackend.java | 10 ++ .../services/AttachFileToConversationRunnable.java | 139 +++++++++++++++++++++ .../messenger/services/NotificationService.java | 12 ++ .../messenger/services/XmppConnectionService.java | 135 ++++---------------- .../utils/SerialSingleThreadExecutor.java | 5 +- 5 files changed, 185 insertions(+), 116 deletions(-) create mode 100644 src/main/java/de/pixart/messenger/services/AttachFileToConversationRunnable.java (limited to 'src/main/java') diff --git a/src/main/java/de/pixart/messenger/persistance/FileBackend.java b/src/main/java/de/pixart/messenger/persistance/FileBackend.java index c0cb0a7bd..ee645c50b 100644 --- a/src/main/java/de/pixart/messenger/persistance/FileBackend.java +++ b/src/main/java/de/pixart/messenger/persistance/FileBackend.java @@ -835,6 +835,16 @@ public class FileBackend { } + public int getMediaRuntime(Uri uri) { + try { + MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever(); + mediaMetadataRetriever.setDataSource(mXmppConnectionService, uri); + return Integer.parseInt(mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)); + } catch (IllegalArgumentException e) { + return 0; + } + } + private Dimensions getImageDimensions(File file) { BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; diff --git a/src/main/java/de/pixart/messenger/services/AttachFileToConversationRunnable.java b/src/main/java/de/pixart/messenger/services/AttachFileToConversationRunnable.java new file mode 100644 index 000000000..707bd6ed4 --- /dev/null +++ b/src/main/java/de/pixart/messenger/services/AttachFileToConversationRunnable.java @@ -0,0 +1,139 @@ +package de.pixart.messenger.services; + +import android.net.Uri; +import android.os.Build; +import android.os.ParcelFileDescriptor; +import android.util.Log; + +import net.ypresto.androidtranscoder.MediaTranscoder; +import net.ypresto.androidtranscoder.format.MediaFormatStrategy; +import net.ypresto.androidtranscoder.format.MediaFormatStrategyPresets; + +import java.io.FileDescriptor; +import java.io.FileNotFoundException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; + +import de.pixart.messenger.Config; +import de.pixart.messenger.R; +import de.pixart.messenger.crypto.PgpEngine; +import de.pixart.messenger.entities.DownloadableFile; +import de.pixart.messenger.entities.Message; +import de.pixart.messenger.persistance.FileBackend; +import de.pixart.messenger.ui.UiCallback; +import de.pixart.messenger.utils.MimeUtils; + +public class AttachFileToConversationRunnable implements Runnable, MediaTranscoder.Listener { + + private final XmppConnectionService mXmppConnectionService; + private final Message message; + private final Uri uri; + private final UiCallback callback; + private final boolean isVideoMessage; + private int currentProgress = -1; + + public AttachFileToConversationRunnable(XmppConnectionService xmppConnectionService, Uri uri, Message message, UiCallback callback) { + this.uri = uri; + this.mXmppConnectionService = xmppConnectionService; + this.message = message; + this.callback = callback; + final String mimeType = MimeUtils.guessMimeTypeFromUri(mXmppConnectionService, uri); + this.isVideoMessage = (mimeType != null && mimeType.startsWith("video/") && (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 || !getFileBackend().useFileAsIs(uri))); + } + + private void processAsFile() { + final String path = mXmppConnectionService.getFileBackend().getOriginalPath(uri); + if (path != null) { + message.setRelativeFilePath(path); + mXmppConnectionService.getFileBackend().updateFileParams(message); + if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) { + mXmppConnectionService.getPgpEngine().encrypt(message, callback); + } else { + callback.success(message); + } + } else { + try { + mXmppConnectionService.getFileBackend().copyFileToPrivateStorage(message, uri); + mXmppConnectionService.getFileBackend().updateFileParams(message); + if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) { + final PgpEngine pgpEngine = mXmppConnectionService.getPgpEngine(); + if (pgpEngine != null) { + pgpEngine.encrypt(message, callback); + } else if (callback != null) { + callback.error(R.string.unable_to_connect_to_keychain, null); + } + } else { + callback.success(message); + } + } catch (FileBackend.FileCopyException e) { + callback.error(e.getResId(), message); + } + } + } + + private void processAsVideo() throws FileNotFoundException { + Log.d(Config.LOGTAG, "processing file as video"); + mXmppConnectionService.startForcingForegroundNotification(); + SimpleDateFormat fileDateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US); + message.setRelativeFilePath(fileDateFormat.format(new Date(message.getTimeSent())) + "_" + message.getUuid().substring(0, 4) + "_komp.mp4"); + final DownloadableFile file = mXmppConnectionService.getFileBackend().getFile(message); + final int runtime = mXmppConnectionService.getFileBackend().getMediaRuntime(uri); + MediaFormatStrategy formatStrategy = runtime >= 8000 ? MediaFormatStrategyPresets.createExportPreset960x540Strategy() : MediaFormatStrategyPresets.createAndroid720pStrategy(); + Log.d(Config.LOGTAG, "runtime " + runtime); + file.getParentFile().mkdirs(); + ParcelFileDescriptor parcelFileDescriptor = mXmppConnectionService.getContentResolver().openFileDescriptor(uri, "r"); + FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor(); + MediaTranscoder.getInstance().transcodeVideo(fileDescriptor, file.getAbsolutePath(), formatStrategy, this); + } + + @Override + public void onTranscodeProgress(double progress) { + final int p = (int) Math.round(progress * 100); + if (p > currentProgress) { + currentProgress = p; + mXmppConnectionService.getNotificationService().updateFileAddingNotification(p, message); + } + } + + @Override + public void onTranscodeCompleted() { + mXmppConnectionService.stopForcingForegroundNotification(); + mXmppConnectionService.getFileBackend().updateFileParams(message); + if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) { + mXmppConnectionService.getPgpEngine().encrypt(message, callback); + } else { + callback.success(message); + } + } + + @Override + public void onTranscodeCanceled() { + mXmppConnectionService.stopForcingForegroundNotification(); + processAsFile(); + } + + @Override + public void onTranscodeFailed(Exception e) { + mXmppConnectionService.stopForcingForegroundNotification(); + Log.d(Config.LOGTAG, "video transcoding failed " + e.getMessage()); + processAsFile(); + } + + @Override + public void run() { + if (isVideoMessage) { + try { + processAsVideo(); + } catch (Throwable e) { + processAsFile(); + } + } else { + processAsFile(); + } + } + + public FileBackend getFileBackend() { + return mXmppConnectionService.fileBackend; + } +} \ No newline at end of file diff --git a/src/main/java/de/pixart/messenger/services/NotificationService.java b/src/main/java/de/pixart/messenger/services/NotificationService.java index f1a43dd28..daeba94e3 100644 --- a/src/main/java/de/pixart/messenger/services/NotificationService.java +++ b/src/main/java/de/pixart/messenger/services/NotificationService.java @@ -767,4 +767,16 @@ public class NotificationService { notificationManager.notify(ERROR_NOTIFICATION_ID, mBuilder.build()); } + + public Notification updateFileAddingNotification(int current, Message message) { + final NotificationManagerCompat notificationManager = NotificationManagerCompat.from(mXmppConnectionService); + NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(mXmppConnectionService); + mBuilder.setContentTitle(mXmppConnectionService.getString(R.string.transcoding_video)); + mBuilder.setProgress(100, current, false); + mBuilder.setSmallIcon(R.drawable.ic_hourglass_empty_white_24dp); + mBuilder.setContentIntent(createContentIntent(message.getConversation())); + Notification notification = mBuilder.build(); + notificationManager.notify(FOREGROUND_NOTIFICATION_ID, notification); + return notification; + } } diff --git a/src/main/java/de/pixart/messenger/services/XmppConnectionService.java b/src/main/java/de/pixart/messenger/services/XmppConnectionService.java index 464df2232..0900a4ec4 100644 --- a/src/main/java/de/pixart/messenger/services/XmppConnectionService.java +++ b/src/main/java/de/pixart/messenger/services/XmppConnectionService.java @@ -21,7 +21,6 @@ import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.IBinder; -import android.os.ParcelFileDescriptor; import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.os.SystemClock; @@ -42,15 +41,11 @@ import net.java.otr4j.session.Session; import net.java.otr4j.session.SessionID; import net.java.otr4j.session.SessionImpl; import net.java.otr4j.session.SessionStatus; -import net.ypresto.androidtranscoder.MediaTranscoder; -import net.ypresto.androidtranscoder.format.MediaFormatStrategyPresets; import org.openintents.openpgp.IOpenPgpService2; import org.openintents.openpgp.util.OpenPgpApi; import org.openintents.openpgp.util.OpenPgpServiceConnection; -import java.io.FileDescriptor; -import java.io.FileNotFoundException; import java.math.BigInteger; import java.net.URL; import java.security.SecureRandom; @@ -62,7 +57,6 @@ import java.util.Arrays; import java.util.Calendar; import java.util.Collection; import java.util.Collections; -import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; @@ -112,7 +106,6 @@ import de.pixart.messenger.persistance.DatabaseBackend; import de.pixart.messenger.persistance.FileBackend; import de.pixart.messenger.ui.SettingsActivity; import de.pixart.messenger.ui.UiCallback; -import de.pixart.messenger.ui.UiInformableCallback; import de.pixart.messenger.utils.ConversationsFileObserver; import de.pixart.messenger.utils.CryptoHelper; import de.pixart.messenger.utils.ExceptionHelper; @@ -190,11 +183,12 @@ public class XmppConnectionService extends Service { startService(intent); } }; - private FileBackend fileBackend = new FileBackend(this); + public FileBackend fileBackend = new FileBackend(this); private MemorizingTrustManager mMemorizingTrustManager; private NotificationService mNotificationService = new NotificationService(this); private ShortcutService mShortcutService = new ShortcutService(this); private AtomicBoolean mInitialAddressbookSyncCompleted = new AtomicBoolean(false); + private AtomicBoolean mForceForegroundService = new AtomicBoolean(false); private OnMessagePacketReceived mMessageParser = new MessageParser(this); private OnPresencePacketReceived mPresenceParser = new PresenceParser(this); private IqParser mIqParser = new IqParser(this); @@ -405,6 +399,16 @@ public class XmppConnectionService extends Service { } } + public void startForcingForegroundNotification() { + mForceForegroundService.set(true); + toggleForegroundService(); + } + + public void stopForcingForegroundNotification() { + mForceForegroundService.set(false); + toggleForegroundService(); + } + private OpenPgpServiceConnection pgpServiceConnection; private PgpEngine mPgpEngine = null; private PowerManager pm; @@ -489,107 +493,8 @@ public class XmppConnectionService extends Service { } message.setCounterpart(conversation.getNextCounterpart()); message.setType(Message.TYPE_FILE); - mFileAddingExecutor.execute(new Runnable() { - private void processAsFile() { - final String path = getFileBackend().getOriginalPath(uri); - if (path != null) { - message.setRelativeFilePath(path); - getFileBackend().updateFileParams(message); - if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) { - getPgpEngine().encrypt(message, callback); - } else { - callback.success(message); - } - } else { - try { - getFileBackend().copyFileToPrivateStorage(message, uri); - getFileBackend().updateFileParams(message); - if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) { - final PgpEngine pgpEngine = getPgpEngine(); - if (pgpEngine != null) { - pgpEngine.encrypt(message, callback); - } else if (callback != null) { - callback.error(R.string.unable_to_connect_to_keychain, null); - } - } else { - callback.success(message); - } - } catch (FileBackend.FileCopyException e) { - callback.error(e.getResId(), message); - } - } - } - - private void processAsVideo() throws FileNotFoundException { - Log.d(Config.LOGTAG, "processing file as video"); - SimpleDateFormat fileDateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US); - message.setRelativeFilePath(fileDateFormat.format(new Date(message.getTimeSent())) + "_" + message.getUuid().substring(0, 4) + "_komp.mp4"); - final DownloadableFile file = getFileBackend().getFile(message); - file.getParentFile().mkdirs(); - ParcelFileDescriptor parcelFileDescriptor = getContentResolver().openFileDescriptor(uri, "r"); - FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor(); - final ArrayList progressTracker = new ArrayList<>(); - final UiInformableCallback informableCallback; - if (callback instanceof UiInformableCallback) { - informableCallback = (UiInformableCallback) callback; - } else { - informableCallback = null; - } - MediaTranscoder.Listener listener = new MediaTranscoder.Listener() { - @Override - public void onTranscodeProgress(double progress) { - int p = ((int) Math.round(progress * 100) / 5) * 5; - if (!progressTracker.contains(p) && p != 100 && p != 0) { - progressTracker.add(p); - if (informableCallback != null) { - informableCallback.inform(getString(R.string.transcoding_video_progress, String.valueOf(p))); - } - } - } - - @Override - public void onTranscodeCompleted() { - getFileBackend().updateFileParams(message); - if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) { - getPgpEngine().encrypt(message, callback); - } else { - callback.success(message); - } - } - - @Override - public void onTranscodeCanceled() { - processAsFile(); - } - - @Override - public void onTranscodeFailed(Exception e) { - Log.d(Config.LOGTAG, "video transcoding failed " + e.getMessage()); - processAsFile(); - } - }; - MediaTranscoder.getInstance().transcodeVideo(fileDescriptor, file.getAbsolutePath(), - MediaFormatStrategyPresets.createAndroidStandardStrategy(getCompressVideoBitratePreference(), getCompressVideoResolutionPreference()), listener); - } - - @Override - public void run() { - final String mimeType = MimeUtils.guessMimeTypeFromUri(XmppConnectionService.this, uri); - if (mimeType != null && mimeType.startsWith("video/") && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { - if (getFileBackend().useFileAsIs(uri)) { - processAsFile(); - } else { - try { - processAsVideo(); - } catch (Throwable e) { - processAsFile(); - } - } - } else { - processAsFile(); - } - } - }); + AttachFileToConversationRunnable runnable = new AttachFileToConversationRunnable(this,uri,message,callback); + mFileAddingExecutor.execute(runnable); } public void attachImageToConversation(final Conversation conversation, final Uri uri, final UiCallback callback) { @@ -1208,20 +1113,22 @@ public class XmppConnectionService extends Service { } public void toggleForegroundService() { - if (showForegroundService()) { + if (mForceForegroundService.get() || (showForegroundService())) { startForeground(NotificationService.FOREGROUND_NOTIFICATION_ID, this.mNotificationService.createForegroundNotification()); + Log.d(Config.LOGTAG, "started foreground service"); } else { stopForeground(true); + Log.d(Config.LOGTAG, "stopped foreground service"); } } @Override public void onTaskRemoved(final Intent rootIntent) { super.onTaskRemoved(rootIntent); - if (!showForegroundService()) { - this.logoutAndSave(false); + if (showForegroundService() || mForceForegroundService.get()) { + Log.d(Config.LOGTAG, "ignoring onTaskRemoved because foreground service is activated"); } else { - Log.d(Config.LOGTAG,"ignoring onTaskRemoved because foreground service is activated"); + this.logoutAndSave(false); } } @@ -4231,6 +4138,8 @@ public class XmppConnectionService extends Service { return mShortcutService; } + + public interface OnMamPreferencesFetched { void onPreferencesFetched(Element prefs); diff --git a/src/main/java/de/pixart/messenger/utils/SerialSingleThreadExecutor.java b/src/main/java/de/pixart/messenger/utils/SerialSingleThreadExecutor.java index 6b60a424f..b4ecf6e5e 100644 --- a/src/main/java/de/pixart/messenger/utils/SerialSingleThreadExecutor.java +++ b/src/main/java/de/pixart/messenger/utils/SerialSingleThreadExecutor.java @@ -3,15 +3,14 @@ package de.pixart.messenger.utils; import android.os.Looper; import java.util.ArrayDeque; -import java.util.Queue; import java.util.concurrent.Executor; import java.util.concurrent.Executors; public class SerialSingleThreadExecutor implements Executor { final Executor executor = Executors.newSingleThreadExecutor(); - protected final Queue tasks = new ArrayDeque(); - Runnable active; + protected final ArrayDeque tasks = new ArrayDeque<>(); + private Runnable active; public SerialSingleThreadExecutor() { this(false); -- cgit v1.2.3