diff options
6 files changed, 159 insertions, 54 deletions
diff --git a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java index faeca6308..c3093f2cf 100644 --- a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java @@ -1496,6 +1496,7 @@ public class FileBackend { DownloadableFile file = getFile(message); final String mime = file.getMimeType(); final boolean privateMessage = message.isPrivateMessage(); + final boolean ambiguous = MimeUtils.AMBIGUOUS_CONTAINER_FORMATS.contains(mime); final boolean image = message.getType() == Message.TYPE_IMAGE || (mime != null && mime.startsWith("image/")); @@ -1507,7 +1508,21 @@ public class FileBackend { body.append(url); } body.append('|').append(file.getSize()); - if (image || video || pdf) { + if (ambiguous) { + try { + final Dimensions dimensions = getVideoDimensions(file); + if (dimensions.valid()) { + Log.d(Config.LOGTAG,"ambiguous file "+mime+" is video"); + body.append('|').append(dimensions.width).append('|').append(dimensions.height); + } else { + Log.d(Config.LOGTAG,"ambiguous file "+mime+" is audio"); + body.append("|0|0|").append(getMediaRuntime(file)); + } + } catch (final NotAVideoFile e) { + Log.d(Config.LOGTAG,"ambiguous file "+mime+" is audio"); + body.append("|0|0|").append(getMediaRuntime(file)); + } + } else if (image || video || pdf) { try { final Dimensions dimensions; if (video) { @@ -1537,14 +1552,16 @@ public class FileBackend { : (image ? Message.TYPE_IMAGE : Message.TYPE_FILE)); } - private int getMediaRuntime(File file) { + private int getMediaRuntime(final File file) { try { - MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever(); + final MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever(); mediaMetadataRetriever.setDataSource(file.toString()); - return Integer.parseInt( - mediaMetadataRetriever.extractMetadata( - MediaMetadataRetriever.METADATA_KEY_DURATION)); - } catch (RuntimeException e) { + final String value = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION); + if (Strings.isNullOrEmpty(value)) { + return 0; + } + return Integer.parseInt(value); + } catch (NumberFormatException e) { return 0; } } diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index a6823e670..b15d9bccb 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -1384,6 +1384,7 @@ public class XmppConnectionService extends Service { final Intent intent = new Intent(this, EventReceiver.class); intent.setAction(ACTION_POST_CONNECTIVITY_CHANGE); try { + //TODO add immutable flag final PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 1, intent, 0); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { alarmManager.setAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtMillis, pendingIntent); @@ -1430,7 +1431,8 @@ public class XmppConnectionService extends Service { final Intent intent = new Intent(this, EventReceiver.class); intent.setAction(ACTION_IDLE_PING); try { - PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0); + //TODO add immutable flag + final PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0); alarmManager.setAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, timeToWake, pendingIntent); } catch (RuntimeException e) { Log.d(Config.LOGTAG, "unable to schedule alarm for idle ping", e); @@ -1443,7 +1445,7 @@ public class XmppConnectionService extends Service { connection.setOnStatusChangedListener(this.statusListener); connection.setOnPresencePacketReceivedListener(this.mPresenceParser); connection.setOnUnregisteredIqPacketReceivedListener(this.mIqParser); - connection.setOnJinglePacketReceivedListener(((a, jp) -> mJingleConnectionManager.deliverPacket(a, jp))); + connection.setOnJinglePacketReceivedListener((mJingleConnectionManager::deliverPacket)); connection.setOnBindListener(this.mOnBindListener); connection.setOnMessageAcknowledgeListener(this.mOnMessageAcknowledgedListener); connection.addOnAdvancedStreamFeaturesAvailableListener(this.mMessageArchiveService); diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java index 662120d84..9822ac004 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java @@ -11,6 +11,7 @@ import androidx.databinding.DataBindingUtil; import androidx.recyclerview.widget.RecyclerView; import com.google.common.base.Optional; +import com.google.common.base.Strings; import java.util.List; @@ -24,11 +25,13 @@ import eu.siacs.conversations.ui.XmppActivity; import eu.siacs.conversations.ui.util.AvatarWorkerTask; import eu.siacs.conversations.ui.util.StyledAttributes; import eu.siacs.conversations.utils.IrregularUnicodeDetector; +import eu.siacs.conversations.utils.MimeUtils; import eu.siacs.conversations.utils.UIHelper; import eu.siacs.conversations.xmpp.Jid; import eu.siacs.conversations.xmpp.jingle.OngoingRtpSession; -public class ConversationAdapter extends RecyclerView.Adapter<ConversationAdapter.ConversationViewHolder> { +public class ConversationAdapter + extends RecyclerView.Adapter<ConversationAdapter.ConversationViewHolder> { private final XmppActivity activity; private final List<Conversation> conversations; @@ -39,11 +42,15 @@ public class ConversationAdapter extends RecyclerView.Adapter<ConversationAdapte this.conversations = conversations; } - @NonNull @Override public ConversationViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - return new ConversationViewHolder(DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.conversation_list_row, parent, false)); + return new ConversationViewHolder( + DataBindingUtil.inflate( + LayoutInflater.from(parent.getContext()), + R.layout.conversation_list_row, + parent, + false)); } @Override @@ -54,15 +61,18 @@ public class ConversationAdapter extends RecyclerView.Adapter<ConversationAdapte } CharSequence name = conversation.getName(); if (name instanceof Jid) { - viewHolder.binding.conversationName.setText(IrregularUnicodeDetector.style(activity, (Jid) name)); + viewHolder.binding.conversationName.setText( + IrregularUnicodeDetector.style(activity, (Jid) name)); } else { viewHolder.binding.conversationName.setText(name); } if (conversation == ConversationFragment.getConversation(activity)) { - viewHolder.binding.frame.setBackgroundColor(StyledAttributes.getColor(activity, R.attr.color_background_tertiary)); + viewHolder.binding.frame.setBackgroundColor( + StyledAttributes.getColor(activity, R.attr.color_background_tertiary)); } else { - viewHolder.binding.frame.setBackgroundColor(StyledAttributes.getColor(activity, R.attr.color_background_primary)); + viewHolder.binding.frame.setBackgroundColor( + StyledAttributes.getColor(activity, R.attr.color_background_primary)); } Message message = conversation.getLatestMessage(); @@ -92,31 +102,70 @@ public class ConversationAdapter extends RecyclerView.Adapter<ConversationAdapte } else { final boolean fileAvailable = !message.isDeleted(); final boolean showPreviewText; - if (fileAvailable && (message.isFileOrImage() || message.treatAsDownloadable() || message.isGeoUri())) { + if (fileAvailable + && (message.isFileOrImage() + || message.treatAsDownloadable() + || message.isGeoUri())) { final int imageResource; if (message.isGeoUri()) { - imageResource = activity.getThemeResource(R.attr.ic_attach_location, R.drawable.ic_attach_location); + imageResource = + activity.getThemeResource( + R.attr.ic_attach_location, R.drawable.ic_attach_location); showPreviewText = false; } else { - //TODO move this into static MediaPreview method and use same icons as in MediaAdapter + // TODO move this into static MediaPreview method and use same icons as in + // MediaAdapter final String mime = message.getMimeType(); - switch (mime == null ? "" : mime.split("/")[0]) { - case "image": - imageResource = activity.getThemeResource(R.attr.ic_attach_photo, R.drawable.ic_attach_photo); - showPreviewText = false; - break; - case "video": - imageResource = activity.getThemeResource(R.attr.ic_attach_videocam, R.drawable.ic_attach_videocam); + if (MimeUtils.AMBIGUOUS_CONTAINER_FORMATS.contains(mime)) { + final Message.FileParams fileParams = message.getFileParams(); + if (fileParams.width > 0 && fileParams.height > 0) { + imageResource = + activity.getThemeResource( + R.attr.ic_attach_videocam, + R.drawable.ic_attach_videocam); showPreviewText = false; - break; - case "audio": - imageResource = activity.getThemeResource(R.attr.ic_attach_record, R.drawable.ic_attach_record); + } else if (fileParams.runtime > 0) { + imageResource = + activity.getThemeResource( + R.attr.ic_attach_record, R.drawable.ic_attach_record); showPreviewText = false; - break; - default: - imageResource = activity.getThemeResource(R.attr.ic_attach_document, R.drawable.ic_attach_document); + } else { + imageResource = + activity.getThemeResource( + R.attr.ic_attach_document, + R.drawable.ic_attach_document); showPreviewText = true; - break; + } + } else { + switch (Strings.nullToEmpty(mime).split("/")[0]) { + case "image": + imageResource = + activity.getThemeResource( + R.attr.ic_attach_photo, R.drawable.ic_attach_photo); + showPreviewText = false; + break; + case "video": + imageResource = + activity.getThemeResource( + R.attr.ic_attach_videocam, + R.drawable.ic_attach_videocam); + showPreviewText = false; + break; + case "audio": + imageResource = + activity.getThemeResource( + R.attr.ic_attach_record, + R.drawable.ic_attach_record); + showPreviewText = false; + break; + default: + imageResource = + activity.getThemeResource( + R.attr.ic_attach_document, + R.drawable.ic_attach_document); + showPreviewText = true; + break; + } } } viewHolder.binding.conversationLastmsgImg.setImageResource(imageResource); @@ -125,13 +174,18 @@ public class ConversationAdapter extends RecyclerView.Adapter<ConversationAdapte viewHolder.binding.conversationLastmsgImg.setVisibility(View.GONE); showPreviewText = true; } - final Pair<CharSequence, Boolean> preview = UIHelper.getMessagePreview(activity, message, viewHolder.binding.conversationLastmsg.getCurrentTextColor()); + final Pair<CharSequence, Boolean> preview = + UIHelper.getMessagePreview( + activity, + message, + viewHolder.binding.conversationLastmsg.getCurrentTextColor()); if (showPreviewText) { viewHolder.binding.conversationLastmsg.setText(UIHelper.shorten(preview.first)); } else { viewHolder.binding.conversationLastmsgImg.setContentDescription(preview.first); } - viewHolder.binding.conversationLastmsg.setVisibility(showPreviewText ? View.VISIBLE : View.GONE); + viewHolder.binding.conversationLastmsg.setVisibility( + showPreviewText ? View.VISIBLE : View.GONE); if (preview.second) { if (isRead) { viewHolder.binding.conversationLastmsg.setTypeface(null, Typeface.ITALIC); @@ -152,7 +206,8 @@ public class ConversationAdapter extends RecyclerView.Adapter<ConversationAdapte if (message.getStatus() == Message.STATUS_RECEIVED) { if (conversation.getMode() == Conversation.MODE_MULTI) { viewHolder.binding.senderName.setVisibility(View.VISIBLE); - viewHolder.binding.senderName.setText(UIHelper.getMessageDisplayName(message).split("\\s+")[0] + ':'); + viewHolder.binding.senderName.setText( + UIHelper.getMessageDisplayName(message).split("\\s+")[0] + ':'); } else { viewHolder.binding.senderName.setVisibility(View.GONE); } @@ -164,33 +219,47 @@ public class ConversationAdapter extends RecyclerView.Adapter<ConversationAdapte } } - final Optional<OngoingRtpSession> ongoingCall; if (conversation.getMode() == Conversational.MODE_MULTI) { ongoingCall = Optional.absent(); } else { - ongoingCall = activity.xmppConnectionService.getJingleConnectionManager().getOngoingRtpConnection(conversation.getContact()); + ongoingCall = + activity.xmppConnectionService + .getJingleConnectionManager() + .getOngoingRtpConnection(conversation.getContact()); } if (ongoingCall.isPresent()) { viewHolder.binding.notificationStatus.setVisibility(View.VISIBLE); - final int ic_ongoing_call = activity.getThemeResource(R.attr.ic_ongoing_call_hint, R.drawable.ic_phone_in_talk_black_18dp); - viewHolder.binding.notificationStatus.setImageResource(ic_ongoing_call); + final int ic_ongoing_call = + activity.getThemeResource( + R.attr.ic_ongoing_call_hint, R.drawable.ic_phone_in_talk_black_18dp); + viewHolder.binding.notificationStatus.setImageResource(ic_ongoing_call); } else { - final long muted_till = conversation.getLongAttribute(Conversation.ATTRIBUTE_MUTED_TILL, 0); + final long muted_till = + conversation.getLongAttribute(Conversation.ATTRIBUTE_MUTED_TILL, 0); if (muted_till == Long.MAX_VALUE) { viewHolder.binding.notificationStatus.setVisibility(View.VISIBLE); - int ic_notifications_off = activity.getThemeResource(R.attr.icon_notifications_off, R.drawable.ic_notifications_off_black_24dp); + int ic_notifications_off = + activity.getThemeResource( + R.attr.icon_notifications_off, + R.drawable.ic_notifications_off_black_24dp); viewHolder.binding.notificationStatus.setImageResource(ic_notifications_off); } else if (muted_till >= System.currentTimeMillis()) { viewHolder.binding.notificationStatus.setVisibility(View.VISIBLE); - int ic_notifications_paused = activity.getThemeResource(R.attr.icon_notifications_paused, R.drawable.ic_notifications_paused_black_24dp); + int ic_notifications_paused = + activity.getThemeResource( + R.attr.icon_notifications_paused, + R.drawable.ic_notifications_paused_black_24dp); viewHolder.binding.notificationStatus.setImageResource(ic_notifications_paused); } else if (conversation.alwaysNotify()) { viewHolder.binding.notificationStatus.setVisibility(View.GONE); } else { viewHolder.binding.notificationStatus.setVisibility(View.VISIBLE); - int ic_notifications_none = activity.getThemeResource(R.attr.icon_notifications_none, R.drawable.ic_notifications_none_black_24dp); + int ic_notifications_none = + activity.getThemeResource( + R.attr.icon_notifications_none, + R.drawable.ic_notifications_none_black_24dp); viewHolder.binding.notificationStatus.setImageResource(ic_notifications_none); } } @@ -201,9 +270,16 @@ public class ConversationAdapter extends RecyclerView.Adapter<ConversationAdapte } else { timestamp = conversation.getLatestMessage().getTimeSent(); } - viewHolder.binding.pinnedOnTop.setVisibility(conversation.getBooleanAttribute(Conversation.ATTRIBUTE_PINNED_ON_TOP,false) ? View.VISIBLE : View.GONE); - viewHolder.binding.conversationLastupdate.setText(UIHelper.readableTimeDifference(activity, timestamp)); - AvatarWorkerTask.loadAvatar(conversation, viewHolder.binding.conversationImage, R.dimen.avatar_on_conversation_overview); + viewHolder.binding.pinnedOnTop.setVisibility( + conversation.getBooleanAttribute(Conversation.ATTRIBUTE_PINNED_ON_TOP, false) + ? View.VISIBLE + : View.GONE); + viewHolder.binding.conversationLastupdate.setText( + UIHelper.readableTimeDifference(activity, timestamp)); + AvatarWorkerTask.loadAvatar( + conversation, + viewHolder.binding.conversationImage, + R.dimen.avatar_on_conversation_overview); viewHolder.itemView.setOnClickListener(v -> listener.onConversationClick(v, conversation)); } @@ -216,7 +292,6 @@ public class ConversationAdapter extends RecyclerView.Adapter<ConversationAdapte this.listener = listener; } - public void insert(Conversation c, int position) { conversations.add(position, c); notifyDataSetChanged(); @@ -238,7 +313,5 @@ public class ConversationAdapter extends RecyclerView.Adapter<ConversationAdapte super(binding.getRoot()); this.binding = binding; } - } - } diff --git a/src/main/java/eu/siacs/conversations/utils/MimeUtils.java b/src/main/java/eu/siacs/conversations/utils/MimeUtils.java index 90f27f65f..d112a9224 100644 --- a/src/main/java/eu/siacs/conversations/utils/MimeUtils.java +++ b/src/main/java/eu/siacs/conversations/utils/MimeUtils.java @@ -22,12 +22,14 @@ import android.provider.OpenableColumns; import android.util.Log; import com.google.common.base.Strings; +import com.google.common.collect.ImmutableList; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Properties; @@ -40,6 +42,13 @@ import eu.siacs.conversations.services.ExportBackupService; * Used to implement java.net.URLConnection and android.webkit.MimeTypeMap. */ public final class MimeUtils { + + public static final List<String> AMBIGUOUS_CONTAINER_FORMATS = ImmutableList.of( + "application/ogg", + "video/3gpp", // .3gp files can contain audio, video or both + "video/3gpp2" + ); + private static final Map<String, String> mimeTypeToExtensionMap = new HashMap<>(); private static final Map<String, String> extensionToMimeTypeMap = new HashMap<>(); @@ -225,7 +234,12 @@ public final class MimeUtils { add("application/x-xcf", "xcf"); add("application/x-xfig", "fig"); add("application/xhtml+xml", "xhtml"); + add("video/3gpp", "3gpp"); + add("video/3gpp", "3gp"); + add("video/3gpp2", "3gpp2"); + add("video/3gpp2", "3g2"); add("audio/3gpp", "3gpp"); + add("audio/3gpp", "3gp"); add("audio/aac", "aac"); add("audio/aac-adts", "aac"); add("audio/amr", "amr"); @@ -365,10 +379,6 @@ public final class MimeUtils { add("text/x-tex", "cls"); add("text/x-vcalendar", "vcs"); add("text/x-vcard", "vcf"); - add("video/3gpp", "3gpp"); - add("video/3gpp", "3gp"); - add("video/3gpp2", "3gpp2"); - add("video/3gpp2", "3g2"); add("video/avi", "avi"); add("video/dl", "dl"); add("video/dv", "dif"); diff --git a/src/main/java/eu/siacs/conversations/utils/UIHelper.java b/src/main/java/eu/siacs/conversations/utils/UIHelper.java index 26732b501..b70bfc558 100644 --- a/src/main/java/eu/siacs/conversations/utils/UIHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/UIHelper.java @@ -477,8 +477,10 @@ public class UIHelper { public static String getFileDescriptionString(final Context context, final Message message) { final String mime = message.getMimeType(); - if (mime == null) { + if (Strings.isNullOrEmpty(mime)) { return context.getString(R.string.file); + } else if (MimeUtils.AMBIGUOUS_CONTAINER_FORMATS.contains(mime)) { + return context.getString(R.string.multimedia_file); } else if (mime.startsWith("audio/")) { return context.getString(R.string.audio); } else if (mime.startsWith("video/")) { diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index ee5cbce81..8b1fd1de3 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -415,6 +415,7 @@ <string name="video">video</string> <string name="image">image</string> <string name="vector_graphic">vector graphic</string> + <string name="multimedia_file">multimedia file</string> <string name="pdf_document">PDF document</string> <string name="apk">Android App</string> <string name="vcard">Contact</string> |