From 95cb2394154a287afcd295590d741096985ff69a Mon Sep 17 00:00:00 2001 From: steckbrief Date: Wed, 4 Jan 2017 19:41:20 +0100 Subject: Added columns to fileparams table: url, original file name, key and iv auto download of files moved from MessageParser to MessageAdapter download and open file representation cleaned up --- .../eu/siacs/conversations/entities/Message.java | 62 +-- .../conversations/http/HttpConnectionManager.java | 12 +- .../conversations/http/HttpDownloadConnection.java | 34 +- .../siacs/conversations/parser/MessageParser.java | 13 +- .../conversations/persistance/FileBackend.java | 13 +- .../conversations/ui/ConversationActivity.java | 6 +- .../conversations/ui/ConversationFragment.java | 5 +- .../conversations/ui/adapter/MessageAdapter.java | 489 +++++++++++---------- .../eu/siacs/conversations/utils/FileUtils.java | 9 + .../eu/siacs/conversations/utils/UIHelper.java | 34 +- 10 files changed, 373 insertions(+), 304 deletions(-) (limited to 'src/main/java/eu') diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index 5abba478..f524fc58 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -9,6 +9,7 @@ import java.net.URL; import de.thedevstack.conversationsplus.entities.FileParams; import de.thedevstack.conversationsplus.enums.FileStatus; +import de.thedevstack.conversationsplus.utils.MessageUtil; import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession; import eu.siacs.conversations.utils.FileUtils; import eu.siacs.conversations.utils.MimeUtils; @@ -339,7 +340,7 @@ public class Message extends AbstractEntity { public void setType(int type) { this.type = type; - if (null != this.fileParams && (type == Message.TYPE_FILE || type == Message.TYPE_IMAGE)) { + if (null == this.fileParams && (type == Message.TYPE_FILE || type == Message.TYPE_IMAGE)) { this.setFileParams(new FileParams()); } } @@ -482,18 +483,6 @@ public class Message extends AbstractEntity { NOT_DECIDED, } - private String extractRelevantExtension(URL url) { - if (url == null) { - return null; - } - String path = url.getPath(); - return extractRelevantExtension(path); - } - - private String extractRelevantExtension(String path) { - return FileUtils.getRelevantExtension(path); - } - public String getMimeType() { // TODO: Move to fileparams if (relativeFilePath != null) { int start = relativeFilePath.lastIndexOf('.') + 1; @@ -504,7 +493,7 @@ public class Message extends AbstractEntity { } } else { try { - return MimeUtils.guessMimeTypeFromExtension(extractRelevantExtension(new URL(this.getBody()))); + return MimeUtils.guessMimeTypeFromExtension(FileUtils.getRelevantExtension(new URL(this.getBody()))); } catch (MalformedURLException e) { return null; } @@ -527,50 +516,9 @@ public class Message extends AbstractEntity { if (mTreatAsDownloadAble != Decision.NOT_DECIDED) { return mTreatAsDownloadAble; } - /** - * there are a few cases where spaces result in an unwanted behavior, e.g. - * "http://example.com/image.jpg" text that will not be shown /abc.png" - * or more than one image link in one message. - */ - if (getBody().contains(" ")) { - mTreatAsDownloadAble = Decision.NEVER; - return mTreatAsDownloadAble; - } - try { - URL url = new URL(body); - if (!url.getProtocol().equalsIgnoreCase("http") && !url.getProtocol().equalsIgnoreCase("https")) { - mTreatAsDownloadAble = Decision.NEVER; - return mTreatAsDownloadAble; - } - String extension = extractRelevantExtension(url); - if (extension == null) { - mTreatAsDownloadAble = Decision.NEVER; - return mTreatAsDownloadAble; - } - String ref = url.getRef(); - boolean encrypted = ref != null && ref.matches("([A-Fa-f0-9]{2}){48}"); - - if (encrypted) { - if (MimeUtils.guessMimeTypeFromExtension(extension) != null) { - mTreatAsDownloadAble = Decision.MUST; - return mTreatAsDownloadAble; - } else { - mTreatAsDownloadAble = Decision.NEVER; - return mTreatAsDownloadAble; - } - } else if (Transferable.VALID_IMAGE_EXTENSIONS.contains(extension) - || Transferable.WELL_KNOWN_EXTENSIONS.contains(extension)) { - mTreatAsDownloadAble = Decision.SHOULD; - return mTreatAsDownloadAble; - } else { - mTreatAsDownloadAble = Decision.NEVER; - return mTreatAsDownloadAble; - } - } catch (MalformedURLException e) { - mTreatAsDownloadAble = Decision.NEVER; - return mTreatAsDownloadAble; - } + MessageUtil.extractFileParamsFromBody(this); + return this.mTreatAsDownloadAble; } public void untie() { diff --git a/src/main/java/eu/siacs/conversations/http/HttpConnectionManager.java b/src/main/java/eu/siacs/conversations/http/HttpConnectionManager.java index a1ad3c01..e3398f93 100644 --- a/src/main/java/eu/siacs/conversations/http/HttpConnectionManager.java +++ b/src/main/java/eu/siacs/conversations/http/HttpConnectionManager.java @@ -19,6 +19,7 @@ import javax.net.ssl.X509TrustManager; import de.thedevstack.conversationsplus.ConversationsPlusApplication; +import de.thedevstack.conversationsplus.utils.MessageUtil; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.services.AbstractConnectionManager; import eu.siacs.conversations.services.XmppConnectionService; @@ -39,10 +40,13 @@ public class HttpConnectionManager extends AbstractConnectionManager { } public static HttpDownloadConnection createNewDownloadConnection(Message message, boolean interactive) { - HttpDownloadConnection connection = new HttpDownloadConnection(INSTANCE); - connection.init(message,interactive); - INSTANCE.downloadConnections.add(connection); - return connection; + if (MessageUtil.needsDownload(message)) { + HttpDownloadConnection connection = new HttpDownloadConnection(INSTANCE); + connection.init(message, interactive); + INSTANCE.downloadConnections.add(connection); + return connection; + } + return null; } public void finishConnection(HttpDownloadConnection connection) { diff --git a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java index 8b905fd1..77b8e333 100644 --- a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java +++ b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java @@ -18,6 +18,7 @@ import javax.net.ssl.SSLHandshakeException; import de.thedevstack.android.logcat.Logging; import de.thedevstack.conversationsplus.ConversationsPlusApplication; import de.thedevstack.conversationsplus.ConversationsPlusPreferences; +import de.thedevstack.conversationsplus.entities.FileParams; import de.thedevstack.conversationsplus.enums.FileStatus; import de.thedevstack.conversationsplus.exceptions.RemoteFileNotFoundException; import de.thedevstack.conversationsplus.utils.MessageUtil; @@ -76,8 +77,22 @@ public class HttpDownloadConnection implements Transferable { this.message = message; this.message.setTransferable(this); try { - mUrl = new URL(message.getFileParams().getUrl()); - final String sUrlFilename = mUrl.getPath().substring(mUrl.getPath().lastIndexOf('/')).toLowerCase(); + String url = (null != message && null != message.getFileParams()) ? message.getFileParams().getUrl() : null; + if (null == url) { + /* + * If this code is reached and the URL is null something went wrong. + * Try again to extract the file parameters from the message. + */ + MessageUtil.extractFileParamsFromBody(message); + url = (null != message.getFileParams()) ? message.getFileParams().getUrl() : null; + if (null == url) { + message.setTreatAsDownloadable(Message.Decision.NEVER); // TODO find sth better + this.cancel(); + return; + } + } + mUrl = new URL(url); + final String sUrlFilename = mUrl.getPath().substring(mUrl.getPath().lastIndexOf('/') + 1).toLowerCase(); final String lastPart = FileUtils.getLastExtension(sUrlFilename); if (!lastPart.isEmpty() && ("pgp".equals(lastPart) || "gpg".equals(lastPart))) { @@ -86,18 +101,25 @@ public class HttpDownloadConnection implements Transferable { && message.getEncryption() != Message.ENCRYPTION_AXOLOTL) { this.message.setEncryption(Message.ENCRYPTION_NONE); } + String extension; + String originalFilename; if (!lastPart.isEmpty() && VALID_CRYPTO_EXTENSIONS.contains(lastPart)) { extension = FileUtils.getSecondToLastExtension(sUrlFilename); + originalFilename = sUrlFilename.replace("." + lastPart, ""); } else { extension = lastPart; + originalFilename = sUrlFilename; } message.setRelativeFilePath(message.getUuid() + "." + extension); this.file = FileBackend.getFile(message, false); - String reference = mUrl.getRef(); - if (reference != null && reference.length() == 96) { - this.file.setKeyAndIv(CryptoHelper.hexToBytes(reference)); - } + + FileParams fileParams = message.getFileParams(); + if (null == fileParams) { + fileParams = new FileParams(); + message.setFileParams(fileParams); + } + fileParams.setOriginalFilename(originalFilename); if ((this.message.getEncryption() == Message.ENCRYPTION_OTR || this.message.getEncryption() == Message.ENCRYPTION_AXOLOTL) diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index 571a29b4..e194f503 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -21,7 +21,6 @@ import de.thedevstack.conversationsplus.utils.AvatarUtil; import eu.siacs.conversations.Config; import eu.siacs.conversations.crypto.OtrService; import eu.siacs.conversations.crypto.axolotl.AxolotlService; -import eu.siacs.conversations.crypto.axolotl.AxolotlService; import eu.siacs.conversations.crypto.axolotl.AxolotlServiceImpl; import eu.siacs.conversations.crypto.axolotl.XmppAxolotlMessage; import eu.siacs.conversations.entities.Account; @@ -30,7 +29,6 @@ import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.MucOptions; -import eu.siacs.conversations.http.HttpConnectionManager; import eu.siacs.conversations.services.AvatarService; import eu.siacs.conversations.services.MessageArchiveService; import eu.siacs.conversations.services.XmppConnectionService; @@ -470,15 +468,16 @@ public class MessageParser extends AbstractParser implements if (message.getEncryption() == Message.ENCRYPTION_NONE || !ConversationsPlusPreferences.dontSaveEncrypted()) { mXmppConnectionService.databaseBackend.createMessage(message); } + MessageUtil.extractFileParamsFromBody(message); + FileParams fileParams = message.getFileParams(); + if (message.treatAsDownloadable() != Message.Decision.NEVER) { + fileParams.setFileStatus(FileStatus.NEEDS_DOWNLOAD); + } if (message.trusted() && message.treatAsDownloadable() != Message.Decision.NEVER && ConversationsPlusPreferences.autoAcceptFileSize() > 0 && (message.isHttpUploaded() || ConversationsPlusPreferences.autoDownloadFileLink())) { - FileParams fileParams = new FileParams(); - fileParams.setFileStatus(FileStatus.NEEDS_DOWNLOAD); - fileParams.setUrl(message.getBody()); - message.setFileParams(fileParams); - HttpConnectionManager.createNewDownloadConnection(message); + // Download this message in MessageAdapter } else { if (query == null) { mXmppConnectionService.getNotificationService().push(message); diff --git a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java index 6f99ef55..c7cf722d 100644 --- a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java @@ -108,7 +108,18 @@ public class FileBackend { } public static DownloadableFile getFile(Message message, boolean decrypted) { - return new DownloadableFile(getFilePath(message, decrypted)); + DownloadableFile downloadableFile = new DownloadableFile(getFilePath(message, decrypted)); + FileParams fileParams = message.getFileParams(); + if (null != fileParams) { + if (null != fileParams.getKey()) { + downloadableFile.setKey(fileParams.getKey()); + } + if (null != fileParams.getIv()) { + downloadableFile.setIv(fileParams.getIv()); + } + } + + return downloadableFile; } protected static String getFilePath(Message message, String extension) { diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index 2a7432dd..4466dd22 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -62,6 +62,7 @@ import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.Transferable; import eu.siacs.conversations.http.HttpConnectionManager; +import eu.siacs.conversations.http.HttpDownloadConnection; import eu.siacs.conversations.persistance.FileBackend; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate; @@ -622,7 +623,10 @@ public class ConversationActivity extends XmppActivity Toast.makeText(this, R.string.not_connected_try_again, Toast.LENGTH_SHORT).show(); } } else if (message.treatAsDownloadable() != Message.Decision.NEVER) { - HttpConnectionManager.createNewDownloadConnection(message, true); + HttpDownloadConnection downloadConnection = HttpConnectionManager.createNewDownloadConnection(message, true); + if (null == downloadConnection) { + Toast.makeText(this, R.string.file_not_on_remote_host, Toast.LENGTH_LONG).show(); + } } } diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index 5068af8d..08f49551 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -693,7 +693,10 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa } private void downloadFile(Message message) { - HttpConnectionManager.createNewDownloadConnection(message,true); + HttpDownloadConnection downloadConnection = HttpConnectionManager.createNewDownloadConnection(message, true); + if (null == downloadConnection) { + Toast.makeText(activity, R.string.file_not_on_remote_host, Toast.LENGTH_LONG).show(); + } } private void cancelTransmission(Message message) { diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java index 509e3b9b..d562dd5e 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -18,9 +18,7 @@ import android.text.style.ForegroundColorSpan; import android.text.style.RelativeSizeSpan; import android.text.style.StyleSpan; import android.text.util.Linkify; -import android.util.DisplayMetrics; import android.util.Patterns; -import android.view.Gravity; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; @@ -33,7 +31,6 @@ import android.widget.TextView; import android.widget.Toast; import java.lang.ref.WeakReference; -import java.net.URL; import java.util.List; import java.util.concurrent.RejectedExecutionException; import java.util.regex.Matcher; @@ -53,6 +50,7 @@ import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.DownloadableFile; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.Transferable; +import eu.siacs.conversations.http.HttpConnectionManager; import eu.siacs.conversations.persistance.FileBackend; import eu.siacs.conversations.providers.ConversationsPlusFileProvider; import eu.siacs.conversations.services.AvatarService; @@ -75,8 +73,6 @@ public class MessageAdapter extends ArrayAdapter { private ConversationActivity activity; - private DisplayMetrics metrics; - private OnContactPictureClicked mOnContactPictureClickedListener; private OnContactPictureLongClicked mOnContactPictureLongClickedListener; @@ -92,7 +88,6 @@ public class MessageAdapter extends ArrayAdapter { public MessageAdapter(ConversationActivity activity, List messages) { super(activity, 0, messages); this.activity = activity; - metrics = getContext().getResources().getDisplayMetrics(); } public void setOnContactPictureClicked(OnContactPictureClicked listener) { @@ -143,14 +138,9 @@ public class MessageAdapter extends ArrayAdapter { boolean multiReceived = message.getConversation().getMode() == Conversation.MODE_MULTI && message.getStatus() <= Message.STATUS_RECEIVED; if (message.hasFileAttached() || message.getTransferable() != null) { - FileParams params = message.getFileParams(); + FileParams params = message.getFileParams(); if (null != params) { - long size = params.getSize(); - if (size > (1.5 * 1024 * 1024)) { - filesize = size / (1024 * 1024)+ " MiB"; - } else if (size > 0) { - filesize = size / 1024 + " KiB"; - } + filesize = UIHelper.getHumanReadableFileSize(params.getSize()); } if (message.getTransferable() != null && message.getTransferable().getStatus() == Transferable.STATUS_FAILED) { @@ -231,15 +221,11 @@ public class MessageAdapter extends ArrayAdapter { String formatedTime = UIHelper.readableTimeDifferenceFull(getContext(), message.getTimeSent()); if (message.getStatus() <= Message.STATUS_RECEIVED) { - if ((filesize != null) && (info != null)) { - viewHolder.time.setText(formatedTime + " \u00B7 " + filesize +" \u00B7 " + info); - } else if ((filesize == null) && (info != null)) { - viewHolder.time.setText(formatedTime + " \u00B7 " + info); - } else if ((filesize != null) && (info == null)) { - viewHolder.time.setText(formatedTime + " \u00B7 " + filesize); - } else { - viewHolder.time.setText(formatedTime); - } + StringBuilder timeText = new StringBuilder(); + timeText.append((null != formatedTime) ? formatedTime + ((null != info || null != filesize) ? " \u00B7 " : "") : ""); + timeText.append((null != filesize) ? filesize + ((null != info) ? " \u00B7 " : "") : ""); + timeText.append((null != info) ? info : ""); + viewHolder.time.setText(timeText); } else { if ((filesize != null) && (info != null)) { viewHolder.time.setText(filesize + " \u00B7 " + info); @@ -408,28 +394,60 @@ public class MessageAdapter extends ArrayAdapter { return count; } - private void displayDownloadableMessage(ViewHolder viewHolder, - final Message message, String text) { + private void displayDownloadButton(ViewHolder viewHolder, String btnText, OnClickListener onClickListener) { + viewHolder.download_button.setVisibility(View.VISIBLE); + viewHolder.download_button.setText(btnText); + viewHolder.download_button.setOnClickListener(onClickListener); + viewHolder.download_button.setOnLongClickListener(openContextMenu); + } + + private void displayFileInfoForFileMessage(final Message message, ViewHolder viewHolder) { + viewHolder.messageBody.setVisibility(View.VISIBLE); + StringBuilder fileInfos = new StringBuilder(); + String filename = UIHelper.getDisplayFilename(message); + fileInfos.append((null != filename && !filename.isEmpty()) ? (filename) : ""); + + int oldAutoLinkMask = viewHolder.messageBody.getAutoLinkMask(); + viewHolder.messageBody.setAutoLinkMask(0); + viewHolder.messageBody.setText(fileInfos); + viewHolder.messageBody.setAutoLinkMask(oldAutoLinkMask); + } + + private void displayDownloadableMessage(ViewHolder viewHolder, final Message message, int resId) { viewHolder.image.setVisibility(View.GONE); - viewHolder.messageBody.setVisibility(View.GONE); - viewHolder.download_button.setVisibility(View.VISIBLE); - viewHolder.download_button.setText(text); - viewHolder.download_button.setOnClickListener(new OnClickListener() { + FileParams fileParams = message.getFileParams(); + String btnText; + if (null != fileParams) { + this.displayFileInfoForFileMessage(message, viewHolder); + btnText = activity.getString(resId, ""); + } else { + viewHolder.messageBody.setVisibility(View.GONE); + btnText = activity.getString(resId, UIHelper.getFileDescriptionString(activity, message)); + } + + this.displayDownloadButton(viewHolder, btnText, new OnClickListener() { @Override public void onClick(View v) { activity.startDownloadable(message); } }); - viewHolder.download_button.setOnLongClickListener(openContextMenu); } private void displayOpenableMessage(ViewHolder viewHolder,final Message message) { viewHolder.image.setVisibility(View.GONE); - viewHolder.messageBody.setVisibility(View.GONE); - viewHolder.download_button.setVisibility(View.VISIBLE); - viewHolder.download_button.setText(activity.getString(R.string.open_x_file, UIHelper.getFileDescriptionString(activity, message))); - viewHolder.download_button.setOnClickListener(new OnClickListener() { + + FileParams fileParams = message.getFileParams(); + String btnText; + if (null != fileParams) { + this.displayFileInfoForFileMessage(message, viewHolder); + btnText = activity.getString(R.string.cplus_open); + } else { + viewHolder.messageBody.setVisibility(View.GONE); + btnText = activity.getString(R.string.open_x_file, UIHelper.getFileDescriptionString(activity, message)); + } + + this.displayDownloadButton(viewHolder, btnText, new OnClickListener() { @Override public void onClick(View v) { @@ -489,6 +507,149 @@ public class MessageAdapter extends ArrayAdapter { viewHolder.image.setOnLongClickListener(openContextMenu); } + private View displayStatusMessage(final Message message, ViewHolder viewHolder) { + if (null != viewHolder) { + final Conversation conversation = message.getConversation(); + + viewHolder.status_message.setVisibility(View.VISIBLE); + viewHolder.contact_picture.setVisibility(View.VISIBLE); + if (conversation.getMode() == Conversation.MODE_SINGLE) { + viewHolder.contact_picture.setImageBitmap(AvatarService.getInstance().get(conversation.getContact(), + activity.getPixel(32))); + viewHolder.contact_picture.setAlpha(0.5f); + } + viewHolder.status_message.setText(message.getBody()); + } + return viewHolder.view; + } + + private void displayFileMessage(final Message message, ViewHolder viewHolder) { + final FileParams fileParams = message.getFileParams(); + String mimeType = (null != fileParams) ? fileParams.getMimeType() : null; + if ((message.getType() == Message.TYPE_IMAGE && message.getEncryption() != Message.ENCRYPTION_PGP && message.getEncryption() != Message.ENCRYPTION_DECRYPTION_FAILED) + || (fileParams != null && fileParams.getWidth() > 0) + || (null != mimeType && mimeType.startsWith("image/"))) { + displayImageMessage(viewHolder, message); + } else if ((message.getType() == Message.TYPE_FILE && message.getEncryption() != Message.ENCRYPTION_PGP && message.getEncryption() != Message.ENCRYPTION_DECRYPTION_FAILED) + && null != fileParams && (FileStatus.NEEDS_DOWNLOAD != fileParams.getFileStatus() || 0 == fileParams.getWidth())) { + displayOpenableMessage(viewHolder, message); + } else if (Message.Decision.NEVER == message.treatAsDownloadable()) { + displayTextMessage(viewHolder, message, getItemViewType(message) == RECEIVED && !message.isValidInSession()); + } else { + displayDownloadableMessage(viewHolder, message, R.string.download_x_file); + } + } + + + private void loadAvatar(Message message, ImageView imageView) { + if (cancelPotentialWork(message, imageView)) { + int avatarPixel = imageView.getResources().getDimensionPixelOffset(R.dimen.msg_avatar_size); + final Bitmap bm = AvatarService.getInstance().get(message, avatarPixel, true); + if (bm != null) { + imageView.setImageBitmap(bm); + imageView.setBackgroundColor(0x00000000); + } else { + imageView.setBackgroundColor(UIHelper.getColorForName(UIHelper.getMessageDisplayName(message))); + imageView.setImageDrawable(null); + final BitmapWorkerTask task = new BitmapWorkerTask(imageView); + final AsyncDrawable asyncDrawable = new AsyncDrawable(activity.getResources(), null, task); + imageView.setImageDrawable(asyncDrawable); + try { + task.execute(message); + } catch (final RejectedExecutionException ignored) { + } + } + } + } + + private void displayAvatar(final Message message, int type, ViewHolder viewHolder) { + if (type == RECEIVED) { + ImageView imageView = viewHolder.contact_picture; + if (null != imageView) { + this.loadAvatar(message, imageView); + imageView.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + if (MessageAdapter.this.mOnContactPictureClickedListener != null) { + MessageAdapter.this.mOnContactPictureClickedListener + .onContactPictureClicked(message); + } + + } + }); + if (message.getConversation().getMode() == Conversation.MODE_MULTI) { + imageView.setOnLongClickListener(new OnLongClickListener() { + + @Override + public boolean onLongClick(View v) { + if (MessageAdapter.this.mOnContactPictureLongClickedListener != null) { + MessageAdapter.this.mOnContactPictureLongClickedListener + .onContactPictureLongClicked(message); + return true; + } else { + return false; + } + } + }); + } + } + } + } + + private View initializeView(int type, ViewGroup parent) { + Integer viewResId = null; + + switch (type) { + case SENT: + viewResId = R.layout.message_sent; + break; + case RECEIVED: + viewResId = R.layout.message_received; + break; + case STATUS: + viewResId = R.layout.message_status; + break; + } + + return activity.getLayoutInflater().inflate(viewResId, parent, false); + } + + private ViewHolder initializeViewHolderAndView(Message message, int type, ViewGroup parent) { + View view = initializeView(type, parent); + ViewHolder viewHolder = new ViewHolder(view); + if (SENT == type + || RECEIVED == type) { + viewHolder.message_box = (LinearLayout) view.findViewById(R.id.message_box); + viewHolder.message_box.setVisibility(View.VISIBLE); + viewHolder.indicator = (ImageView) view.findViewById(R.id.security_indicator); + viewHolder.messageBody = (TextView) view.findViewById(R.id.message_body); + viewHolder.time = (TextView) view.findViewById(R.id.message_time); + viewHolder.indicatorReceived = (ImageView) view.findViewById(R.id.indicator_received); + } + if ((SENT == type + || RECEIVED == type)) { + viewHolder.download_button = (Button) view.findViewById(R.id.download_button); + viewHolder.image = (ImageView) view.findViewById(R.id.message_image); + } + if (RECEIVED == type) { // Extra block as preparation for new /me representation + viewHolder.contact_picture = (ImageView) view.findViewById(R.id.message_photo); + viewHolder.contact_picture.setVisibility(View.VISIBLE); + } + if (RECEIVED == type) { + viewHolder.encryption = (TextView) view.findViewById(R.id.message_encryption); + } + if (STATUS == type) { + viewHolder.contact_picture = (ImageView) view.findViewById(R.id.message_photo); + viewHolder.contact_picture.setVisibility(View.VISIBLE); + viewHolder.status_message = (TextView) view.findViewById(R.id.status_message); + viewHolder.status_message.setVisibility(View.VISIBLE); + } + view.setTag(viewHolder); + + return viewHolder; + } + @Override public View getView(int position, View view, ViewGroup parent) { final Message message = getItem(position); @@ -496,180 +657,81 @@ public class MessageAdapter extends ArrayAdapter { final Conversation conversation = message.getConversation(); final Account account = conversation.getAccount(); final int type = getItemViewType(position); - ViewHolder viewHolder; - if (view == null) { - viewHolder = new ViewHolder(); - switch (type) { - case SENT: - view = activity.getLayoutInflater().inflate( - R.layout.message_sent, parent, false); - viewHolder.message_box = (LinearLayout) view - .findViewById(R.id.message_box); - viewHolder.contact_picture = (ImageView) view - .findViewById(R.id.message_photo); - viewHolder.download_button = (Button) view - .findViewById(R.id.download_button); - viewHolder.indicator = (ImageView) view - .findViewById(R.id.security_indicator); - viewHolder.image = (ImageView) view - .findViewById(R.id.message_image); - viewHolder.messageBody = (TextView) view - .findViewById(R.id.message_body); - viewHolder.time = (TextView) view - .findViewById(R.id.message_time); - viewHolder.indicatorReceived = (ImageView) view - .findViewById(R.id.indicator_received); - viewHolder.remoteFileStatus = (TextView) view.findViewById(R.id.remote_file_status); - break; - case RECEIVED: - view = activity.getLayoutInflater().inflate( - R.layout.message_received, parent, false); - viewHolder.message_box = (LinearLayout) view - .findViewById(R.id.message_box); - viewHolder.contact_picture = (ImageView) view - .findViewById(R.id.message_photo); - viewHolder.download_button = (Button) view - .findViewById(R.id.download_button); - viewHolder.indicator = (ImageView) view - .findViewById(R.id.security_indicator); - viewHolder.image = (ImageView) view - .findViewById(R.id.message_image); - viewHolder.messageBody = (TextView) view - .findViewById(R.id.message_body); - viewHolder.time = (TextView) view - .findViewById(R.id.message_time); - viewHolder.indicatorReceived = (ImageView) view - .findViewById(R.id.indicator_received); - viewHolder.encryption = (TextView) view.findViewById(R.id.message_encryption); - break; - case STATUS: - view = activity.getLayoutInflater().inflate(R.layout.message_status, parent, false); - viewHolder.contact_picture = (ImageView) view.findViewById(R.id.message_photo); - viewHolder.status_message = (TextView) view.findViewById(R.id.status_message); - break; - default: - viewHolder = null; - break; - } - view.setTag(viewHolder); - } else { - viewHolder = (ViewHolder) view.getTag(); - if (viewHolder == null) { - return view; - } - } - - boolean darkBackground = (type == RECEIVED && !isInValidSession); - - if (type == STATUS) { - viewHolder.status_message.setVisibility(View.VISIBLE); - viewHolder.contact_picture.setVisibility(View.VISIBLE); - if (conversation.getMode() == Conversation.MODE_SINGLE) { - viewHolder.contact_picture.setImageBitmap(AvatarService.getInstance().get(conversation.getContact(), - activity.getPixel(32))); - viewHolder.contact_picture.setAlpha(0.5f); - } - viewHolder.status_message.setText(message.getBody()); - return view; - } else { - loadAvatar(message, viewHolder.contact_picture); - } + ViewHolder viewHolder; + if (null == view) { + viewHolder = initializeViewHolderAndView(message, type, parent); + view = viewHolder.view; + } else { + viewHolder = (ViewHolder) view.getTag(); + if (null == viewHolder) { + return view; + } + } - viewHolder.contact_picture - .setOnClickListener(new OnClickListener() { + if (type == STATUS) { + return displayStatusMessage(message, viewHolder); + } - @Override - public void onClick(View v) { - if (MessageAdapter.this.mOnContactPictureClickedListener != null) { - MessageAdapter.this.mOnContactPictureClickedListener - .onContactPictureClicked(message); - } + this.displayAvatar(message, type, viewHolder); - } - }); - viewHolder.contact_picture - .setOnLongClickListener(new OnLongClickListener() { - - @Override - public boolean onLongClick(View v) { - if (MessageAdapter.this.mOnContactPictureLongClickedListener != null) { - MessageAdapter.this.mOnContactPictureLongClickedListener - .onContactPictureLongClicked(message); - return true; - } else { - return false; - } - } - }); + boolean darkBackground = (type == RECEIVED && !isInValidSession); + this.displayStatus(viewHolder, message, type, darkBackground); final Transferable transferable = message.getTransferable(); - if (transferable != null && transferable.getStatus() != Transferable.STATUS_UPLOADING) { - if (transferable.getStatus() == Transferable.STATUS_OFFER) { - displayDownloadableMessage(viewHolder,message,activity.getString(R.string.download_x_file, UIHelper.getFileDescriptionString(activity, message))); - } else if (transferable.getStatus() == Transferable.STATUS_OFFER_CHECK_FILESIZE) { - displayDownloadableMessage(viewHolder, message, activity.getString(R.string.check_x_filesize, UIHelper.getFileDescriptionString(activity, message))); - } else { - displayInfoMessage(viewHolder, UIHelper.getMessagePreview(activity, message).first,darkBackground); - } - } else if (message.getType() == Message.TYPE_IMAGE && message.getEncryption() != Message.ENCRYPTION_PGP && message.getEncryption() != Message.ENCRYPTION_DECRYPTION_FAILED) { - displayImageMessage(viewHolder, message); - } else if (message.getType() == Message.TYPE_FILE && message.getEncryption() != Message.ENCRYPTION_PGP && message.getEncryption() != Message.ENCRYPTION_DECRYPTION_FAILED) { - if (message.getFileParams() != null && message.getFileParams().getWidth() > 0) { // TODO Use FileParams.getMimeType() - displayImageMessage(viewHolder,message); - } else { - displayOpenableMessage(viewHolder, message); - } - } else if (message.getEncryption() == Message.ENCRYPTION_PGP) { - if (activity.hasPgp()) { - if (account.getPgpDecryptionService().isRunning()) { - displayInfoMessage(viewHolder, activity.getString(R.string.message_decrypting), darkBackground); - } else { - displayInfoMessage(viewHolder, activity.getString(R.string.pgp_message), darkBackground); - } - } else { - displayInfoMessage(viewHolder,activity.getString(R.string.install_openkeychain),darkBackground); - if (viewHolder != null) { - viewHolder.message_box - .setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - activity.showInstallPgpDialog(); - } - }); - } - } - } else if (message.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) { - displayDecryptionFailed(viewHolder,darkBackground); - } else if (message.hasFileAttached()) { // TODO: Move to a single block with Message.TYPE_FILE OR Message.TYPE_IMAGE - FileParams fileParams = message.getFileParams(); - String mimeType = (null != fileParams) ? fileParams.getMimeType() : null; - if (null != mimeType && mimeType.startsWith("image/")) { - displayImageMessage(viewHolder, message); + if (null != transferable) { + switch (transferable.getStatus()) { + case Transferable.STATUS_OFFER: + displayDownloadableMessage(viewHolder, message, R.string.download_x_file); + break; + case Transferable.STATUS_OFFER_CHECK_FILESIZE: + displayDownloadableMessage(viewHolder, message, R.string.check_x_filesize); + break; + case Transferable.STATUS_UPLOADING: + displayFileMessage(message, viewHolder); + break; + case Transferable.STATUS_DELETED: + case Transferable.STATUS_CHECKING: + case Transferable.STATUS_FAILED: + case Transferable.STATUS_UNKNOWN: + displayInfoMessage(viewHolder, UIHelper.getMessagePreview(activity, message).first,darkBackground); + break; + } + } else if (message.hasFileAttached()) { + if (message.trusted() + && MessageUtil.needsDownload(message) + && ConversationsPlusPreferences.autoAcceptFileSize() > 0 + && (message.isHttpUploaded() || ConversationsPlusPreferences.autoDownloadFileLink())) { + HttpConnectionManager.createNewDownloadConnection(message); + } else { + displayFileMessage(message, viewHolder); + } + } else if (GeoHelper.isGeoUri(message.getBody())) { + displayLocationMessage(viewHolder, message); + } else if (message.getEncryption() == Message.ENCRYPTION_PGP) { + if (activity.hasPgp()) { + if (account.getPgpDecryptionService().isRunning()) { + displayInfoMessage(viewHolder, activity.getString(R.string.message_decrypting), darkBackground); + } else { + displayInfoMessage(viewHolder, activity.getString(R.string.pgp_message), darkBackground); + } } else { - displayOpenableMessage(viewHolder, message); + displayInfoMessage(viewHolder,activity.getString(R.string.install_openkeychain),darkBackground); + if (viewHolder != null) { + viewHolder.message_box + .setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + activity.showInstallPgpDialog(); + } + }); + } } + } else if (message.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) { + displayDecryptionFailed(viewHolder,darkBackground); } else { - if (GeoHelper.isGeoUri(message.getBody())) { - displayLocationMessage(viewHolder,message); - } else if (MessageUtil.needsDownload(message)) { - try { - URL url = new URL(message.getFileParams().getUrl()); - displayDownloadableMessage(viewHolder, - message, - activity.getString(R.string.check_x_filesize_on_host, - UIHelper.getFileDescriptionString(activity, message), - url.getHost())); - } catch (Exception e) { - displayDownloadableMessage(viewHolder, - message, - activity.getString(R.string.check_x_filesize, - UIHelper.getFileDescriptionString(activity, message))); - } - } else { - displayTextMessage(viewHolder, message, darkBackground); - } - } + displayTextMessage(viewHolder, message, darkBackground); + } if (type == RECEIVED) { if(isInValidSession) { @@ -681,8 +743,6 @@ public class MessageAdapter extends ArrayAdapter { } } - displayStatus(viewHolder, message, type, darkBackground); - return view; } @@ -750,6 +810,10 @@ public class MessageAdapter extends ArrayAdapter { } private static class ViewHolder { + protected ViewHolder(View view) { + this.view = view; + } + protected View view; protected LinearLayout message_box; protected Button download_button; @@ -774,7 +838,8 @@ public class MessageAdapter extends ArrayAdapter { @Override protected Bitmap doInBackground(Message... params) { - return AvatarService.getInstance().get(params[0], activity.getPixel(48), isCancelled()); + int avatarPixel = activity.getResources().getDimensionPixelOffset(R.dimen.msg_avatar_size); + return AvatarService.getInstance().get(params[0], avatarPixel, isCancelled()); } @Override @@ -789,26 +854,6 @@ public class MessageAdapter extends ArrayAdapter { } } - public void loadAvatar(Message message, ImageView imageView) { - if (cancelPotentialWork(message, imageView)) { - final Bitmap bm = AvatarService.getInstance().get(message, activity.getPixel(48), true); - if (bm != null) { - imageView.setImageBitmap(bm); - imageView.setBackgroundColor(0x00000000); - } else { - imageView.setBackgroundColor(UIHelper.getColorForName(UIHelper.getMessageDisplayName(message))); - imageView.setImageDrawable(null); - final BitmapWorkerTask task = new BitmapWorkerTask(imageView); - final AsyncDrawable asyncDrawable = new AsyncDrawable(activity.getResources(), null, task); - imageView.setImageDrawable(asyncDrawable); - try { - task.execute(message); - } catch (final RejectedExecutionException ignored) { - } - } - } - } - public static boolean cancelPotentialWork(Message message, ImageView imageView) { final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView); diff --git a/src/main/java/eu/siacs/conversations/utils/FileUtils.java b/src/main/java/eu/siacs/conversations/utils/FileUtils.java index 18014894..3633025f 100644 --- a/src/main/java/eu/siacs/conversations/utils/FileUtils.java +++ b/src/main/java/eu/siacs/conversations/utils/FileUtils.java @@ -13,6 +13,7 @@ import android.provider.MediaStore; import android.provider.OpenableColumns; import java.io.File; +import java.net.URL; import java.util.List; import de.thedevstack.conversationsplus.ConversationsPlusApplication; @@ -162,6 +163,14 @@ public final class FileUtils { return "com.android.providers.media.documents".equals(uri.getAuthority()); } + public static String getRelevantExtension(URL url) { + if (url == null) { + return null; + } + String path = url.getPath(); + return getRelevantExtension(path); + } + public static String getRelevantExtension(String path) { if (path == null || path.isEmpty()) { return null; diff --git a/src/main/java/eu/siacs/conversations/utils/UIHelper.java b/src/main/java/eu/siacs/conversations/utils/UIHelper.java index a97b16a4..d9cdd34c 100644 --- a/src/main/java/eu/siacs/conversations/utils/UIHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/UIHelper.java @@ -14,6 +14,7 @@ import java.util.Locale; import de.thedevstack.conversationsplus.ConversationsPlusColors; +import de.thedevstack.conversationsplus.entities.FileParams; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; @@ -211,16 +212,26 @@ public class UIHelper { } else if (mime.startsWith("image/")) { return context.getString(R.string.image); } else if (mime.contains("pdf")) { - return context.getString(R.string.pdf_document) ; + return context.getString(R.string.pdf_document); } else if (mime.contains("application/vnd.android.package-archive")) { - return context.getString(R.string.apk) ; + return context.getString(R.string.apk); } else if (mime.contains("vcard")) { - return context.getString(R.string.vcard) ; + return context.getString(R.string.vcard); } else { - return message.getRelativeFilePath(); + String filename = getDisplayFilename(message); + if (null == filename) { + return context.getString(R.string.file); + } else { + return filename; + } } } + public static String getDisplayFilename(final Message message) { + String originalFilename = (null != message.getFileParams()) ? message.getFileParams().getOriginalFilename() : null; + return (null != originalFilename) ? originalFilename : message.getRelativeFilePath(); + } + public static String getMessageDisplayName(final Message message) { final Conversation conversation = message.getConversation(); if (message.getStatus() == Message.STATUS_RECEIVED) { @@ -281,7 +292,20 @@ public class UIHelper { return LOCATION_QUESTIONS.contains(body); } - public static String getHumanReadableFileSize(long filesize) { + public static String getHumanReadableFileSize(long size) { + String filesize; + if (size > (1.5 * 1024 * 1024)) { + filesize = size / (1024 * 1024)+ " MiB"; + } else if (size > 0) { + filesize = size / 1024 + " KiB"; + } else { + filesize = null; + } + + return filesize; + } + + public static String getHumanReadableDetailedFileSize(long filesize) { if (0 > filesize) { return "?"; } -- cgit v1.2.3