parent
5aeed63844
commit
b3a3f2b930
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
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 "video":
|
||||
imageResource = activity.getThemeResource(R.attr.ic_attach_videocam, R.drawable.ic_attach_videocam);
|
||||
} else if (fileParams.runtime > 0) {
|
||||
imageResource =
|
||||
activity.getThemeResource(
|
||||
R.attr.ic_attach_record, R.drawable.ic_attach_record);
|
||||
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);
|
||||
} 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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/")) {
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in a new issue