show permanent notification while transcoding video
This commit is contained in:
parent
17e70f55a0
commit
0603378c75
|
@ -0,0 +1,134 @@
|
||||||
|
package eu.siacs.conversations.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.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.Config;
|
||||||
|
import eu.siacs.conversations.R;
|
||||||
|
import eu.siacs.conversations.crypto.PgpEngine;
|
||||||
|
import eu.siacs.conversations.entities.DownloadableFile;
|
||||||
|
import eu.siacs.conversations.entities.Message;
|
||||||
|
import eu.siacs.conversations.persistance.FileBackend;
|
||||||
|
import eu.siacs.conversations.ui.UiCallback;
|
||||||
|
import eu.siacs.conversations.utils.MimeUtils;
|
||||||
|
|
||||||
|
public class AttachFileToConversationRunnable implements Runnable, MediaTranscoder.Listener {
|
||||||
|
|
||||||
|
private final XmppConnectionService mXmppConnectionService;
|
||||||
|
private final Message message;
|
||||||
|
private final Uri uri;
|
||||||
|
private final UiCallback<Message> callback;
|
||||||
|
private final boolean isVideoMessage;
|
||||||
|
private int currentProgress = -1;
|
||||||
|
|
||||||
|
public AttachFileToConversationRunnable(XmppConnectionService xmppConnectionService, Uri uri, Message message, UiCallback<Message> 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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();
|
||||||
|
message.setRelativeFilePath(message.getUuid() + ".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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -739,4 +739,16 @@ public class NotificationService {
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT));
|
PendingIntent.FLAG_UPDATE_CURRENT));
|
||||||
notificationManager.notify(ERROR_NOTIFICATION_ID, mBuilder.build());
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -189,6 +189,7 @@ public class XmppConnectionService extends Service {
|
||||||
private NotificationService mNotificationService = new NotificationService(this);
|
private NotificationService mNotificationService = new NotificationService(this);
|
||||||
private ShortcutService mShortcutService = new ShortcutService(this);
|
private ShortcutService mShortcutService = new ShortcutService(this);
|
||||||
private AtomicBoolean mInitialAddressbookSyncCompleted = new AtomicBoolean(false);
|
private AtomicBoolean mInitialAddressbookSyncCompleted = new AtomicBoolean(false);
|
||||||
|
private AtomicBoolean mForceForegroundService = new AtomicBoolean(false);
|
||||||
private OnMessagePacketReceived mMessageParser = new MessageParser(this);
|
private OnMessagePacketReceived mMessageParser = new MessageParser(this);
|
||||||
private OnPresencePacketReceived mPresenceParser = new PresenceParser(this);
|
private OnPresencePacketReceived mPresenceParser = new PresenceParser(this);
|
||||||
private IqParser mIqParser = new IqParser(this);
|
private IqParser mIqParser = new IqParser(this);
|
||||||
|
@ -398,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 OpenPgpServiceConnection pgpServiceConnection;
|
||||||
private PgpEngine mPgpEngine = null;
|
private PgpEngine mPgpEngine = null;
|
||||||
private WakeLock wakeLock;
|
private WakeLock wakeLock;
|
||||||
|
@ -483,106 +494,8 @@ public class XmppConnectionService extends Service {
|
||||||
}
|
}
|
||||||
message.setCounterpart(conversation.getNextCounterpart());
|
message.setCounterpart(conversation.getNextCounterpart());
|
||||||
message.setType(Message.TYPE_FILE);
|
message.setType(Message.TYPE_FILE);
|
||||||
mFileAddingExecutor.execute(new Runnable() {
|
AttachFileToConversationRunnable runnable = new AttachFileToConversationRunnable(this,uri,message,callback);
|
||||||
|
mFileAddingExecutor.execute(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");
|
|
||||||
message.setRelativeFilePath(message.getUuid() + ".mp4");
|
|
||||||
final DownloadableFile file = getFileBackend().getFile(message);
|
|
||||||
final int runtime = getFileBackend().getMediaRuntime(uri);
|
|
||||||
MediaFormatStrategy formatStrategy = runtime >= 8000 ? MediaFormatStrategyPresets.createExportPreset960x540Strategy() : MediaFormatStrategyPresets.createAndroid720pStrategy();
|
|
||||||
Log.d(Config.LOGTAG,"runtime "+runtime);
|
|
||||||
file.getParentFile().mkdirs();
|
|
||||||
ParcelFileDescriptor parcelFileDescriptor = getContentResolver().openFileDescriptor(uri, "r");
|
|
||||||
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
|
|
||||||
final ArrayList<Integer> progressTracker = new ArrayList<>();
|
|
||||||
final UiInformableCallback<Message> informableCallback;
|
|
||||||
if (callback instanceof UiInformableCallback) {
|
|
||||||
informableCallback = (UiInformableCallback<Message>) callback;
|
|
||||||
} else {
|
|
||||||
informableCallback = null;
|
|
||||||
}
|
|
||||||
MediaTranscoder.Listener listener = new MediaTranscoder.Listener() {
|
|
||||||
@Override
|
|
||||||
public void onTranscodeProgress(double progress) {
|
|
||||||
int p = ((int) Math.round(progress * 100) / 20) * 20;
|
|
||||||
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(), formatStrategy, 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) {
|
|
||||||
try {
|
|
||||||
processAsVideo();
|
|
||||||
} catch (Throwable e) {
|
|
||||||
processAsFile();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
processAsFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void attachImageToConversation(final Conversation conversation, final Uri uri, final UiCallback<Message> callback) {
|
public void attachImageToConversation(final Conversation conversation, final Uri uri, final UiCallback<Message> callback) {
|
||||||
|
@ -1095,10 +1008,12 @@ public class XmppConnectionService extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void toggleForegroundService() {
|
public void toggleForegroundService() {
|
||||||
if (keepForegroundService() && hasEnabledAccounts()) {
|
if (mForceForegroundService.get() || (keepForegroundService() && hasEnabledAccounts())) {
|
||||||
startForeground(NotificationService.FOREGROUND_NOTIFICATION_ID, this.mNotificationService.createForegroundNotification());
|
startForeground(NotificationService.FOREGROUND_NOTIFICATION_ID, this.mNotificationService.createForegroundNotification());
|
||||||
|
Log.d(Config.LOGTAG,"started foreground service");
|
||||||
} else {
|
} else {
|
||||||
stopForeground(true);
|
stopForeground(true);
|
||||||
|
Log.d(Config.LOGTAG,"stopped foreground service");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1109,10 +1024,10 @@ public class XmppConnectionService extends Service {
|
||||||
@Override
|
@Override
|
||||||
public void onTaskRemoved(final Intent rootIntent) {
|
public void onTaskRemoved(final Intent rootIntent) {
|
||||||
super.onTaskRemoved(rootIntent);
|
super.onTaskRemoved(rootIntent);
|
||||||
if (!keepForegroundService()) {
|
if (keepForegroundService() || mForceForegroundService.get()) {
|
||||||
this.logoutAndSave(false);
|
|
||||||
} else {
|
|
||||||
Log.d(Config.LOGTAG,"ignoring onTaskRemoved because foreground service is activated");
|
Log.d(Config.LOGTAG,"ignoring onTaskRemoved because foreground service is activated");
|
||||||
|
} else {
|
||||||
|
this.logoutAndSave(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,11 +7,13 @@ import java.util.Queue;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.services.AttachFileToConversationRunnable;
|
||||||
|
|
||||||
public class SerialSingleThreadExecutor implements Executor {
|
public class SerialSingleThreadExecutor implements Executor {
|
||||||
|
|
||||||
final Executor executor = Executors.newSingleThreadExecutor();
|
final Executor executor = Executors.newSingleThreadExecutor();
|
||||||
protected final Queue<Runnable> tasks = new ArrayDeque();
|
protected final ArrayDeque<Runnable> tasks = new ArrayDeque<>();
|
||||||
Runnable active;
|
private Runnable active;
|
||||||
|
|
||||||
public SerialSingleThreadExecutor() {
|
public SerialSingleThreadExecutor() {
|
||||||
this(false);
|
this(false);
|
||||||
|
|
BIN
src/main/res/drawable-hdpi/ic_hourglass_empty_white_24dp.png
Normal file
BIN
src/main/res/drawable-hdpi/ic_hourglass_empty_white_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 159 B |
BIN
src/main/res/drawable-mdpi/ic_hourglass_empty_white_24dp.png
Normal file
BIN
src/main/res/drawable-mdpi/ic_hourglass_empty_white_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 135 B |
BIN
src/main/res/drawable-xhdpi/ic_hourglass_empty_white_24dp.png
Normal file
BIN
src/main/res/drawable-xhdpi/ic_hourglass_empty_white_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 174 B |
BIN
src/main/res/drawable-xxhdpi/ic_hourglass_empty_white_24dp.png
Normal file
BIN
src/main/res/drawable-xxhdpi/ic_hourglass_empty_white_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 255 B |
BIN
src/main/res/drawable-xxxhdpi/ic_hourglass_empty_white_24dp.png
Normal file
BIN
src/main/res/drawable-xxxhdpi/ic_hourglass_empty_white_24dp.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 273 B |
|
@ -700,7 +700,7 @@
|
||||||
<string name="pref_automatically_delete_messages_description">Automatically delete messages from this device that are older than the configured time frame.</string>
|
<string name="pref_automatically_delete_messages_description">Automatically delete messages from this device that are older than the configured time frame.</string>
|
||||||
<string name="encrypting_message">Encrypting message</string>
|
<string name="encrypting_message">Encrypting message</string>
|
||||||
<string name="not_fetching_history_retention_period">Not fetching messages due to local retention period.</string>
|
<string name="not_fetching_history_retention_period">Not fetching messages due to local retention period.</string>
|
||||||
<string name="transcoding_video_progress">Compressing video (%s%% completed)</string>
|
<string name="transcoding_video">Compressing video</string>
|
||||||
<string name="corresponding_conversations_closed">Corresponding conversations closed.</string>
|
<string name="corresponding_conversations_closed">Corresponding conversations closed.</string>
|
||||||
<string name="contact_blocked_past_tense">Contact blocked.</string>
|
<string name="contact_blocked_past_tense">Contact blocked.</string>
|
||||||
<string name="pref_notifications_from_strangers">Notifications from strangers</string>
|
<string name="pref_notifications_from_strangers">Notifications from strangers</string>
|
||||||
|
|
Loading…
Reference in a new issue