From 7a90ca429bb46fae4cbd600bd4c2274f4a731a16 Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Thu, 13 Nov 2014 21:04:05 +0100 Subject: [PATCH 01/13] basic arbitrary file transfer --- .../conversations/entities/Downloadable.java | 6 +- .../entities/DownloadableFile.java | 12 ++ .../siacs/conversations/entities/Message.java | 25 +++- .../conversations/http/HttpConnection.java | 15 ++ .../persistance/DatabaseBackend.java | 7 +- .../persistance/FileBackend.java | 73 +++++++--- .../services/XmppConnectionService.java | 39 ++++- .../ui/ConversationActivity.java | 46 ++++-- .../ui/adapter/MessageAdapter.java | 99 ++++++++----- .../xmpp/jingle/JingleConnection.java | 133 ++++++++++-------- .../xmpp/jingle/JingleSocks5Transport.java | 8 ++ src/main/res/menu/attachment_choices.xml | 3 +- src/main/res/values/strings.xml | 6 +- 13 files changed, 334 insertions(+), 138 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/entities/Downloadable.java b/src/main/java/eu/siacs/conversations/entities/Downloadable.java index e4c853367..cc0dc157f 100644 --- a/src/main/java/eu/siacs/conversations/entities/Downloadable.java +++ b/src/main/java/eu/siacs/conversations/entities/Downloadable.java @@ -2,7 +2,7 @@ package eu.siacs.conversations.entities; public interface Downloadable { - public final String[] VALID_EXTENSIONS = {"webp", "jpeg", "jpg", "png", "jpe"}; + public final String[] VALID_IMAGE_EXTENSIONS = {"webp", "jpeg", "jpg", "png", "jpe"}; public final String[] VALID_CRYPTO_EXTENSIONS = {"pgp", "gpg", "otr"}; public static final int STATUS_UNKNOWN = 0x200; @@ -18,4 +18,8 @@ public interface Downloadable { public int getStatus(); public long getFileSize(); + + public int getProgress(); + + public String getMimeType(); } diff --git a/src/main/java/eu/siacs/conversations/entities/DownloadableFile.java b/src/main/java/eu/siacs/conversations/entities/DownloadableFile.java index 1605c75b4..6aff643a0 100644 --- a/src/main/java/eu/siacs/conversations/entities/DownloadableFile.java +++ b/src/main/java/eu/siacs/conversations/entities/DownloadableFile.java @@ -6,6 +6,7 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; +import java.net.URLConnection; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.Key; @@ -28,6 +29,7 @@ public class DownloadableFile extends File { private long expectedSize = 0; private String sha1sum; private Key aeskey; + private String mime; private byte[] iv = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0xf }; @@ -52,6 +54,16 @@ public class DownloadableFile extends File { } } + public String getMimeType() { + if (mime==null) { + mime = URLConnection.guessContentTypeFromName(this.getAbsolutePath()); + if (mime == null) { + mime = ""; + } + } + return mime; + } + public void setExpectedSize(long size) { this.expectedSize = size; } diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index 5b44435e8..33f3443b7 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -32,7 +32,7 @@ public class Message extends AbstractEntity { public static final int TYPE_TEXT = 0; public static final int TYPE_IMAGE = 1; - public static final int TYPE_AUDIO = 2; + public static final int TYPE_FILE = 2; public static final int TYPE_STATUS = 3; public static final int TYPE_PRIVATE = 4; @@ -45,6 +45,7 @@ public class Message extends AbstractEntity { public static String STATUS = "status"; public static String TYPE = "type"; public static String REMOTE_MSG_ID = "remoteMsgId"; + public static String RELATIVE_FILE_PATH = "relativeFilePath"; public boolean markable = false; protected String conversationUuid; protected Jid counterpart; @@ -55,6 +56,7 @@ public class Message extends AbstractEntity { protected int encryption; protected int status; protected int type; + protected String relativeFilePath; protected boolean read = true; protected String remoteMsgId = null; protected Conversation conversation = null; @@ -74,13 +76,13 @@ public class Message extends AbstractEntity { this(java.util.UUID.randomUUID().toString(), conversation.getUuid(), conversation.getContactJid().toBareJid(), null, body, System .currentTimeMillis(), encryption, - status, TYPE_TEXT, null); + status, TYPE_TEXT, null,null); this.conversation = conversation; } public Message(final String uuid, final String conversationUUid, final Jid counterpart, final String trueCounterpart, final String body, final long timeSent, - final int encryption, final int status, final int type, final String remoteMsgId) { + final int encryption, final int status, final int type, final String remoteMsgId, final String relativeFilePath) { this.uuid = uuid; this.conversationUuid = conversationUUid; this.counterpart = counterpart; @@ -91,6 +93,7 @@ public class Message extends AbstractEntity { this.status = status; this.type = type; this.remoteMsgId = remoteMsgId; + this.relativeFilePath = relativeFilePath; } public static Message fromCursor(Cursor cursor) { @@ -114,7 +117,8 @@ public class Message extends AbstractEntity { cursor.getInt(cursor.getColumnIndex(ENCRYPTION)), cursor.getInt(cursor.getColumnIndex(STATUS)), cursor.getInt(cursor.getColumnIndex(TYPE)), - cursor.getString(cursor.getColumnIndex(REMOTE_MSG_ID))); + cursor.getString(cursor.getColumnIndex(REMOTE_MSG_ID)), + cursor.getString(cursor.getColumnIndex(RELATIVE_FILE_PATH))); } public static Message createStatusMessage(Conversation conversation) { @@ -141,6 +145,7 @@ public class Message extends AbstractEntity { values.put(STATUS, status); values.put(TYPE, type); values.put(REMOTE_MSG_ID, remoteMsgId); + values.put(RELATIVE_FILE_PATH, relativeFilePath); return values; } @@ -205,6 +210,14 @@ public class Message extends AbstractEntity { this.status = status; } + public void setRelativeFilePath(String path) { + this.relativeFilePath = path; + } + + public String getRelativeFilePath() { + return this.relativeFilePath; + } + public String getRemoteMsgId() { return this.remoteMsgId; } @@ -376,14 +389,14 @@ public class Message extends AbstractEntity { } String[] extensionParts = filename.split("\\."); if (extensionParts.length == 2 - && Arrays.asList(Downloadable.VALID_EXTENSIONS).contains( + && Arrays.asList(Downloadable.VALID_IMAGE_EXTENSIONS).contains( extensionParts[extensionParts.length - 1])) { return true; } else if (extensionParts.length == 3 && Arrays .asList(Downloadable.VALID_CRYPTO_EXTENSIONS) .contains(extensionParts[extensionParts.length - 1]) - && Arrays.asList(Downloadable.VALID_EXTENSIONS).contains( + && Arrays.asList(Downloadable.VALID_IMAGE_EXTENSIONS).contains( extensionParts[extensionParts.length - 2])) { return true; } else { diff --git a/src/main/java/eu/siacs/conversations/http/HttpConnection.java b/src/main/java/eu/siacs/conversations/http/HttpConnection.java index 147ac42f2..fd6b9c1a1 100644 --- a/src/main/java/eu/siacs/conversations/http/HttpConnection.java +++ b/src/main/java/eu/siacs/conversations/http/HttpConnection.java @@ -37,6 +37,7 @@ public class HttpConnection implements Downloadable { private DownloadableFile file; private int mStatus = Downloadable.STATUS_UNKNOWN; private boolean acceptedAutomatically = false; + private int mProgress = 0; public HttpConnection(HttpConnectionManager manager) { this.mHttpConnectionManager = manager; @@ -235,10 +236,14 @@ public class HttpConnection implements Downloadable { if (os == null) { throw new IOException(); } + long transmitted = 0; + long expected = file.getExpectedSize(); int count = -1; byte[] buffer = new byte[1024]; while ((count = is.read(buffer)) != -1) { + transmitted += count; os.write(buffer, 0, count); + mProgress = (int) (expected * 100 / transmitted); } os.flush(); os.close(); @@ -272,4 +277,14 @@ public class HttpConnection implements Downloadable { return 0; } } + + @Override + public int getProgress() { + return this.mProgress; + } + + @Override + public String getMimeType() { + return ""; + } } \ No newline at end of file diff --git a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java index 310c8f420..38f4fdf13 100644 --- a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java @@ -22,7 +22,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { private static DatabaseBackend instance = null; private static final String DATABASE_NAME = "history"; - private static final int DATABASE_VERSION = 9; + private static final int DATABASE_VERSION = 10; private static String CREATE_CONTATCS_STATEMENT = "create table " + Contact.TABLENAME + "(" + Contact.ACCOUNT + " TEXT, " @@ -64,6 +64,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { + " TEXT, " + Message.TRUE_COUNTERPART + " TEXT," + Message.BODY + " TEXT, " + Message.ENCRYPTION + " NUMBER, " + Message.STATUS + " NUMBER," + Message.TYPE + " NUMBER, " + + Message.RELATIVE_FILE_PATH + " TEXT, " + Message.REMOTE_MSG_ID + " TEXT, FOREIGN KEY(" + Message.CONVERSATION + ") REFERENCES " + Conversation.TABLENAME + "(" + Conversation.UUID @@ -110,6 +111,10 @@ public class DatabaseBackend extends SQLiteOpenHelper { db.execSQL("ALTER TABLE " + Contact.TABLENAME + " ADD COLUMN " + Contact.LAST_PRESENCE + " TEXT"); } + if (oldVersion < 10 && newVersion >= 10) { + db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN " + + Message.RELATIVE_FILE_PATH + " TEXT"); + } } public static synchronized DatabaseBackend getInstance(Context context) { diff --git a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java index 0241b77e8..f052bd532 100644 --- a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java @@ -2,11 +2,13 @@ package eu.siacs.conversations.persistance; import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.net.URLConnection; import java.security.DigestOutputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -14,6 +16,7 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; +import android.content.ContentResolver; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; @@ -53,25 +56,34 @@ public class FileBackend { } public DownloadableFile getFile(Message message, boolean decrypted) { - StringBuilder filename = new StringBuilder(); - filename.append(getConversationsDirectory()); - filename.append(message.getUuid()); - if ((decrypted) || (message.getEncryption() == Message.ENCRYPTION_NONE)) { - filename.append(".webp"); + String path = message.getRelativeFilePath(); + if (path != null && !path.isEmpty()) { + if (path.startsWith("/")) { + return new DownloadableFile(path); + } else { + return new DownloadableFile(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)+"/"+path); + } } else { - if (message.getEncryption() == Message.ENCRYPTION_OTR) { + StringBuilder filename = new StringBuilder(); + filename.append(getConversationsDirectory()); + filename.append(message.getUuid()); + if ((decrypted) || (message.getEncryption() == Message.ENCRYPTION_NONE)) { filename.append(".webp"); } else { - filename.append(".webp.pgp"); + if (message.getEncryption() == Message.ENCRYPTION_OTR) { + filename.append(".webp"); + } else { + filename.append(".webp.pgp"); + } } + return new DownloadableFile(filename.toString()); } - return new DownloadableFile(filename.toString()); } public static String getConversationsDirectory() { return Environment.getExternalStoragePublicDirectory( - Environment.DIRECTORY_PICTURES).getAbsolutePath() - + "/Conversations/"; + Environment.DIRECTORY_PICTURES).getAbsolutePath() + + "/Conversations/"; } public Bitmap resize(Bitmap originalBitmap, int size) { @@ -103,13 +115,34 @@ public class FileBackend { return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true); } + public String getOriginalPath(Uri uri) { + String path = null; + if (uri.getScheme().equals("file")) { + path = uri.getPath(); + } else { + String[] projection = {MediaStore.MediaColumns.DATA}; + Cursor metaCursor = mXmppConnectionService.getContentResolver().query(uri, + projection, null, null, null); + if (metaCursor != null) { + try { + if (metaCursor.moveToFirst()) { + path = metaCursor.getString(0); + } + } finally { + metaCursor.close(); + } + } + } + return path; + } + public DownloadableFile copyImageToPrivateStorage(Message message, Uri image) - throws ImageCopyException { + throws FileCopyException { return this.copyImageToPrivateStorage(message, image, 0); } private DownloadableFile copyImageToPrivateStorage(Message message, - Uri image, int sampleSize) throws ImageCopyException { + Uri image, int sampleSize) throws FileCopyException { try { InputStream is = mXmppConnectionService.getContentResolver() .openInputStream(image); @@ -125,7 +158,7 @@ public class FileBackend { originalBitmap = BitmapFactory.decodeStream(is, null, options); is.close(); if (originalBitmap == null) { - throw new ImageCopyException(R.string.error_not_an_image_file); + throw new FileCopyException(R.string.error_not_an_image_file); } Bitmap scalledBitmap = resize(originalBitmap, IMAGE_SIZE); originalBitmap = null; @@ -137,7 +170,7 @@ public class FileBackend { boolean success = scalledBitmap.compress( Bitmap.CompressFormat.WEBP, 75, os); if (!success) { - throw new ImageCopyException(R.string.error_compressing_image); + throw new FileCopyException(R.string.error_compressing_image); } os.flush(); os.close(); @@ -147,18 +180,18 @@ public class FileBackend { message.setBody(Long.toString(size) + ',' + width + ',' + height); return file; } catch (FileNotFoundException e) { - throw new ImageCopyException(R.string.error_file_not_found); + throw new FileCopyException(R.string.error_file_not_found); } catch (IOException e) { - throw new ImageCopyException(R.string.error_io_exception); + throw new FileCopyException(R.string.error_io_exception); } catch (SecurityException e) { - throw new ImageCopyException( + throw new FileCopyException( R.string.error_security_exception_during_image_copy); } catch (OutOfMemoryError e) { ++sampleSize; if (sampleSize <= 3) { return copyImageToPrivateStorage(message, image, sampleSize); } else { - throw new ImageCopyException(R.string.error_out_of_memory); + throw new FileCopyException(R.string.error_out_of_memory); } } } @@ -400,11 +433,11 @@ public class FileBackend { return Uri.parse("file://" + file.getAbsolutePath()); } - public class ImageCopyException extends Exception { + public class FileCopyException extends Exception { private static final long serialVersionUID = -1010013599132881427L; private int resId; - public ImageCopyException(int resId) { + public FileCopyException(int resId) { this.resId = resId; } diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 831a54e12..36ccc6325 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -56,6 +56,7 @@ import eu.siacs.conversations.entities.Bookmark; import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Downloadable; +import eu.siacs.conversations.entities.DownloadableFile; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.MucOptions; import eu.siacs.conversations.entities.MucOptions.OnRenameListener; @@ -294,6 +295,27 @@ public class XmppConnectionService extends Service { return this.mAvatarService; } + public Message attachFileToConversation(Conversation conversation, final Uri uri) { + String path = getFileBackend().getOriginalPath(uri); + if (path!=null) { + Log.d(Config.LOGTAG,"file path : "+path); + Message message; + if (conversation.getNextEncryption(forceEncryption()) == Message.ENCRYPTION_PGP) { + message = new Message(conversation, "", + Message.ENCRYPTION_DECRYPTED); + } else { + message = new Message(conversation, "", + conversation.getNextEncryption(forceEncryption())); + } + message.setCounterpart(conversation.getNextCounterpart()); + message.setType(Message.TYPE_FILE); + message.setStatus(Message.STATUS_OFFERED); + message.setRelativeFilePath(path); + return message; + } + return null; + } + public Message attachImageToConversation(final Conversation conversation, final Uri uri, final UiCallback callback) { final Message message; @@ -312,13 +334,14 @@ public class XmppConnectionService extends Service { @Override public void run() { try { - getFileBackend().copyImageToPrivateStorage(message, uri); + DownloadableFile file = getFileBackend().copyImageToPrivateStorage(message, uri); + message.setRelativeFilePath(file.getName()); if (conversation.getNextEncryption(forceEncryption()) == Message.ENCRYPTION_PGP) { getPgpEngine().encrypt(message, callback); } else { callback.success(message); } - } catch (FileBackend.ImageCopyException e) { + } catch (FileBackend.FileCopyException e) { callback.error(e.getResId(), message); } } @@ -552,7 +575,7 @@ public class XmppConnectionService extends Service { boolean send = false; if (account.getStatus() == Account.STATUS_ONLINE && account.getXmppConnection() != null) { - if (message.getType() == Message.TYPE_IMAGE) { + if (message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE) { if (message.getCounterpart() != null) { if (message.getEncryption() == Message.ENCRYPTION_OTR) { if (!conv.hasValidOtrSession()) { @@ -1988,5 +2011,15 @@ public class XmppConnectionService extends Service { return 0; } + @Override + public int getProgress() { + return 0; + } + + @Override + public String getMimeType() { + return ""; + } + } } diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index 5d11bb597..8c2f9dab4 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -15,6 +15,7 @@ import android.os.SystemClock; import android.provider.MediaStore; import android.support.v4.widget.SlidingPaneLayout; import android.support.v4.widget.SlidingPaneLayout.PanelSlideListener; +import android.util.Log; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; @@ -31,6 +32,7 @@ import android.widget.Toast; import java.util.ArrayList; import java.util.List; +import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; @@ -52,13 +54,14 @@ public class ConversationActivity extends XmppActivity implements public static final int REQUEST_SEND_MESSAGE = 0x0201; public static final int REQUEST_DECRYPT_PGP = 0x0202; public static final int REQUEST_ENCRYPT_MESSAGE = 0x0207; - private static final int REQUEST_ATTACH_FILE_DIALOG = 0x0203; + private static final int REQUEST_ATTACH_IMAGE_DIALOG = 0x0203; private static final int REQUEST_IMAGE_CAPTURE = 0x0204; private static final int REQUEST_RECORD_AUDIO = 0x0205; private static final int REQUEST_SEND_PGP_IMAGE = 0x0206; + private static final int REQUEST_ATTACH_FILE_DIALOG = 0x0208; private static final int ATTACHMENT_CHOICE_CHOOSE_IMAGE = 0x0301; private static final int ATTACHMENT_CHOICE_TAKE_PHOTO = 0x0302; - private static final int ATTACHMENT_CHOICE_RECORD_VOICE = 0x0303; + private static final int ATTACHMENT_CHOICE_CHOOSE_FILE = 0x0303; private static final String STATE_OPEN_CONVERSATION = "state_open_conversation"; private static final String STATE_PANEL_OPEN = "state_panel_open"; private static final String STATE_PENDING_URI = "state_pending_uri"; @@ -66,6 +69,7 @@ public class ConversationActivity extends XmppActivity implements private String mOpenConverstaion = null; private boolean mPanelOpen = true; private Uri mPendingImageUri = null; + private Uri mPendingFileUri = null; private View mContentView; @@ -306,13 +310,16 @@ public class ConversationActivity extends XmppActivity implements Intent attachFileIntent = new Intent(); attachFileIntent.setType("image/*"); attachFileIntent.setAction(Intent.ACTION_GET_CONTENT); + Intent chooser = Intent.createChooser(attachFileIntent, + getString(R.string.attach_file)); + startActivityForResult(chooser, REQUEST_ATTACH_IMAGE_DIALOG); + } else if (attachmentChoice == ATTACHMENT_CHOICE_CHOOSE_FILE) { + Intent attachFileIntent = new Intent(); + attachFileIntent.setType("file/*"); + attachFileIntent.setAction(Intent.ACTION_GET_CONTENT); Intent chooser = Intent.createChooser(attachFileIntent, getString(R.string.attach_file)); startActivityForResult(chooser, REQUEST_ATTACH_FILE_DIALOG); - } else if (attachmentChoice == ATTACHMENT_CHOICE_RECORD_VOICE) { - Intent intent = new Intent( - MediaStore.Audio.Media.RECORD_SOUND_ACTION); - startActivityForResult(intent, REQUEST_RECORD_AUDIO); } } }); @@ -483,7 +490,7 @@ public class ConversationActivity extends XmppActivity implements attachFile(ATTACHMENT_CHOICE_TAKE_PHOTO); break; case R.id.attach_record_voice: - attachFile(ATTACHMENT_CHOICE_RECORD_VOICE); + attachFile(ATTACHMENT_CHOICE_CHOOSE_FILE); break; } return false; @@ -675,14 +682,17 @@ public class ConversationActivity extends XmppActivity implements } else { showConversationsOverview(); mPendingImageUri = null; + mPendingFileUri = null; setSelectedConversation(conversationList.get(0)); this.mConversationFragment.reInit(getSelectedConversation()); } if (mPendingImageUri != null) { - attachImageToConversation(getSelectedConversation(), - mPendingImageUri); + attachImageToConversation(getSelectedConversation(),mPendingImageUri); mPendingImageUri = null; + } else if (mPendingFileUri != null) { + attachFileToConversation(getSelectedConversation(),mPendingFileUri); + mPendingFileUri = null; } ExceptionHelper.checkForCrash(this, this.xmppConnectionService); setIntent(new Intent()); @@ -726,13 +736,20 @@ public class ConversationActivity extends XmppActivity implements selectedFragment.hideSnackbar(); selectedFragment.updateMessages(); } - } else if (requestCode == REQUEST_ATTACH_FILE_DIALOG) { + } else if (requestCode == REQUEST_ATTACH_IMAGE_DIALOG) { mPendingImageUri = data.getData(); if (xmppConnectionServiceBound) { attachImageToConversation(getSelectedConversation(), mPendingImageUri); mPendingImageUri = null; } + } else if (requestCode == REQUEST_ATTACH_FILE_DIALOG) { + mPendingFileUri = data.getData(); + if (xmppConnectionServiceBound) { + attachFileToConversation(getSelectedConversation(), + mPendingFileUri); + mPendingFileUri = null; + } } else if (requestCode == REQUEST_SEND_PGP_IMAGE) { } else if (requestCode == ATTACHMENT_CHOICE_CHOOSE_IMAGE) { @@ -754,9 +771,6 @@ public class ConversationActivity extends XmppActivity implements Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); intent.setData(mPendingImageUri); sendBroadcast(intent); - } else if (requestCode == REQUEST_RECORD_AUDIO) { - attachAudioToConversation(getSelectedConversation(), - data.getData()); } } else { if (requestCode == REQUEST_IMAGE_CAPTURE) { @@ -765,8 +779,10 @@ public class ConversationActivity extends XmppActivity implements } } - private void attachAudioToConversation(Conversation conversation, Uri uri) { - + private void attachFileToConversation(Conversation conversation, Uri uri) { + Log.d(Config.LOGTAG, "attachFileToConversation"); + Message message = xmppConnectionService.attachFileToConversation(conversation,uri); + xmppConnectionService.sendMessage(message); } private void attachImageToConversation(Conversation conversation, Uri uri) { 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 3ebb93908..6449a6f91 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -2,15 +2,18 @@ package eu.siacs.conversations.ui.adapter; import android.content.Intent; import android.graphics.Typeface; +import android.net.Uri; import android.text.Spannable; import android.text.SpannableString; import android.text.style.ForegroundColorSpan; import android.text.style.StyleSpan; import android.util.DisplayMetrics; +import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; import android.view.ViewGroup; +import android.webkit.MimeTypeMap; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.ImageView; @@ -18,6 +21,9 @@ import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; import java.util.List; import eu.siacs.conversations.Config; @@ -25,6 +31,7 @@ import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Downloadable; +import eu.siacs.conversations.entities.DownloadableFile; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.Message.ImageParams; import eu.siacs.conversations.ui.ConversationActivity; @@ -181,13 +188,13 @@ public class MessageAdapter extends ArrayAdapter { } } - private void displayInfoMessage(ViewHolder viewHolder, int r) { + private void displayInfoMessage(ViewHolder viewHolder, String text) { if (viewHolder.download_button != null) { viewHolder.download_button.setVisibility(View.GONE); } viewHolder.image.setVisibility(View.GONE); viewHolder.messageBody.setVisibility(View.VISIBLE); - viewHolder.messageBody.setText(getContext().getString(r)); + viewHolder.messageBody.setText(text); viewHolder.messageBody.setTextColor(activity.getSecondaryTextColor()); viewHolder.messageBody.setTypeface(null, Typeface.ITALIC); viewHolder.messageBody.setTextIsSelectable(false); @@ -252,11 +259,11 @@ public class MessageAdapter extends ArrayAdapter { } private void displayDownloadableMessage(ViewHolder viewHolder, - final Message message, int resid) { + final Message message, String text) { viewHolder.image.setVisibility(View.GONE); viewHolder.messageBody.setVisibility(View.GONE); viewHolder.download_button.setVisibility(View.VISIBLE); - viewHolder.download_button.setText(resid); + viewHolder.download_button.setText(text); viewHolder.download_button.setOnClickListener(new OnClickListener() { @Override @@ -267,6 +274,21 @@ public class MessageAdapter extends ArrayAdapter { 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_file,activity.xmppConnectionService.getFileBackend().getFile(message).getMimeType())); + viewHolder.download_button.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + openDonwloadable(message); + } + }); + viewHolder.download_button.setOnLongClickListener(openContextMenu); + } + private void displayImageMessage(ViewHolder viewHolder, final Message message) { if (viewHolder.download_button != null) { @@ -455,42 +477,46 @@ public class MessageAdapter extends ArrayAdapter { }); } - if (item.getType() == Message.TYPE_IMAGE - || item.getDownloadable() != null) { + if (item.getDownloadable() != null) { Downloadable d = item.getDownloadable(); - if (d != null && d.getStatus() == Downloadable.STATUS_DOWNLOADING) { - displayInfoMessage(viewHolder, R.string.receiving_image); - } else if (d != null - && d.getStatus() == Downloadable.STATUS_CHECKING) { - displayInfoMessage(viewHolder, R.string.checking_image); - } else if (d != null - && d.getStatus() == Downloadable.STATUS_DELETED) { - displayInfoMessage(viewHolder, R.string.image_file_deleted); - } else if (d != null && d.getStatus() == Downloadable.STATUS_OFFER) { - displayDownloadableMessage(viewHolder, item, - R.string.download_image); - } else if (d != null - && d.getStatus() == Downloadable.STATUS_OFFER_CHECK_FILESIZE) { - displayDownloadableMessage(viewHolder, item, - R.string.check_image_filesize); - } else if (d != null && d.getStatus() == Downloadable.STATUS_FAILED) { - displayInfoMessage(viewHolder, R.string.image_transmission_failed); - } else if ((item.getEncryption() == Message.ENCRYPTION_DECRYPTED) - || (item.getEncryption() == Message.ENCRYPTION_NONE) - || (item.getEncryption() == Message.ENCRYPTION_OTR)) { - displayImageMessage(viewHolder, item); - } else if (item.getEncryption() == Message.ENCRYPTION_PGP) { - displayInfoMessage(viewHolder, R.string.encrypted_message); - } else { - displayDecryptionFailed(viewHolder); + if (d.getStatus() == Downloadable.STATUS_DOWNLOADING) { + if (item.getType() == Message.TYPE_FILE) { + displayInfoMessage(viewHolder,activity.getString(R.string.receiving_file,d.getMimeType(),d.getProgress())); + } else { + displayInfoMessage(viewHolder,activity.getString(R.string.receiving_image,d.getProgress())); + } + } else if (d.getStatus() == Downloadable.STATUS_CHECKING) { + displayInfoMessage(viewHolder,activity.getString(R.string.checking_image)); + } else if (d.getStatus() == Downloadable.STATUS_DELETED) { + displayInfoMessage(viewHolder,activity.getString(R.string.image_file_deleted)); + } else if (d.getStatus() == Downloadable.STATUS_OFFER) { + if (item.getType() == Message.TYPE_FILE) { + displayDownloadableMessage(viewHolder,item,activity.getString(R.string.download_file,d.getMimeType())); + } else { + displayDownloadableMessage(viewHolder, item,activity.getString(R.string.download_image)); + } + } else if (d.getStatus() == Downloadable.STATUS_OFFER_CHECK_FILESIZE) { + displayDownloadableMessage(viewHolder, item,activity.getString(R.string.check_image_filesize)); + } else if (d.getStatus() == Downloadable.STATUS_FAILED) { + displayInfoMessage(viewHolder, activity.getString(R.string.image_transmission_failed)); } + } else if (item.getType() == Message.TYPE_IMAGE) { + if (item.getEncryption() == Message.ENCRYPTION_PGP) { + displayInfoMessage(viewHolder,activity.getString(R.string.encrypted_message)); + } else if (item.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) { + displayDecryptionFailed(viewHolder); + } else { + displayImageMessage(viewHolder, item); + } + } else if (item.getType() == Message.TYPE_FILE) { + displayOpenableMessage(viewHolder,item); } else { if (item.getEncryption() == Message.ENCRYPTION_PGP) { if (activity.hasPgp()) { - displayInfoMessage(viewHolder, R.string.encrypted_message); + displayInfoMessage(viewHolder,activity.getString(R.string.encrypted_message)); } else { displayInfoMessage(viewHolder, - R.string.install_openkeychain); + activity.getString(R.string.install_openkeychain)); if (viewHolder != null) { viewHolder.message_box .setOnClickListener(new OnClickListener() { @@ -524,6 +550,13 @@ public class MessageAdapter extends ArrayAdapter { } } + public void openDonwloadable(Message message) { + DownloadableFile file = activity.xmppConnectionService.getFileBackend().getFile(message); + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setDataAndType(Uri.fromFile(file), file.getMimeType()); + getContext().startActivity(intent); + } + public interface OnContactPictureClicked { public void onContactPictureClicked(Message message); } diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java index 30e1c7da0..3208cab4b 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java @@ -11,6 +11,7 @@ import java.util.concurrent.ConcurrentHashMap; import android.content.Intent; import android.graphics.BitmapFactory; import android.net.Uri; +import android.os.SystemClock; import android.util.Log; import eu.siacs.conversations.Config; import eu.siacs.conversations.entities.Account; @@ -29,9 +30,6 @@ import eu.siacs.conversations.xmpp.stanzas.IqPacket; public class JingleConnection implements Downloadable { - private final String[] extensions = { "webp", "jpeg", "jpg", "png" }; - private final String[] cryptoExtensions = { "pgp", "gpg", "otr" }; - private JingleConnectionManager mJingleConnectionManager; private XmppConnectionService mXmppConnectionService; @@ -62,6 +60,9 @@ public class JingleConnection implements Downloadable { private String contentName; private String contentCreator; + private int mProgress = 0; + private long mLastGuiRefresh = 0; + private boolean receivedCandidate = false; private boolean sentCandidate = false; @@ -258,7 +259,6 @@ public class JingleConnection implements Downloadable { packet.getFrom().toBareJid(), false); this.message = new Message(conversation, "", Message.ENCRYPTION_NONE); this.message.setStatus(Message.STATUS_RECEIVED); - this.message.setType(Message.TYPE_IMAGE); this.mStatus = Downloadable.STATUS_OFFER; this.message.setDownloadable(this); final Jid from = packet.getFrom(); @@ -278,68 +278,71 @@ public class JingleConnection implements Downloadable { Element fileSize = fileOffer.findChild("size"); Element fileNameElement = fileOffer.findChild("name"); if (fileNameElement != null) { - boolean supportedFile = false; String[] filename = fileNameElement.getContent() .toLowerCase(Locale.US).split("\\."); - if (Arrays.asList(this.extensions).contains( + if (Arrays.asList(VALID_IMAGE_EXTENSIONS).contains( filename[filename.length - 1])) { - supportedFile = true; - } else if (Arrays.asList(this.cryptoExtensions).contains( + message.setType(Message.TYPE_IMAGE); + } else if (Arrays.asList(VALID_CRYPTO_EXTENSIONS).contains( filename[filename.length - 1])) { if (filename.length == 3) { - if (Arrays.asList(this.extensions).contains( + if (Arrays.asList(VALID_IMAGE_EXTENSIONS).contains( filename[filename.length - 2])) { - supportedFile = true; - if (filename[filename.length - 1].equals("otr")) { - Log.d(Config.LOGTAG, "receiving otr file"); - this.message - .setEncryption(Message.ENCRYPTION_OTR); - } else { - this.message - .setEncryption(Message.ENCRYPTION_PGP); - } - } - } - } - if (supportedFile) { - long size = Long.parseLong(fileSize.getContent()); - message.setBody(Long.toString(size)); - conversation.add(message); - mXmppConnectionService.updateConversationUi(); - if (size <= this.mJingleConnectionManager - .getAutoAcceptFileSize()) { - Log.d(Config.LOGTAG, "auto accepting file from " - + packet.getFrom()); - this.acceptedAutomatically = true; - this.sendAccept(); - } else { - message.markUnread(); - Log.d(Config.LOGTAG, - "not auto accepting new file offer with size: " - + size - + " allowed size:" - + this.mJingleConnectionManager - .getAutoAcceptFileSize()); - this.mXmppConnectionService.getNotificationService() - .push(message); - } - this.file = this.mXmppConnectionService.getFileBackend() - .getFile(message, false); - if (message.getEncryption() == Message.ENCRYPTION_OTR) { - byte[] key = conversation.getSymmetricKey(); - if (key == null) { - this.sendCancel(); - this.cancel(); - return; + message.setType(Message.TYPE_IMAGE); } else { - this.file.setKey(key); + message.setType(Message.TYPE_FILE); + } + if (filename[filename.length - 1].equals("otr")) { + message.setEncryption(Message.ENCRYPTION_OTR); + } else { + message.setEncryption(Message.ENCRYPTION_PGP); } } - this.file.setExpectedSize(size); } else { - this.sendCancel(); - this.cancel(); + message.setType(Message.TYPE_FILE); } + if (message.getType() == Message.TYPE_FILE) { + String suffix = ""; + if (!fileNameElement.getContent().isEmpty()) { + String parts[] = fileNameElement.getContent().split("/"); + suffix = parts[parts.length - 1]; + } + message.setRelativeFilePath(message.getUuid()+"_"+suffix); + } + long size = Long.parseLong(fileSize.getContent()); + message.setBody(Long.toString(size)); + conversation.add(message); + mXmppConnectionService.updateConversationUi(); + if (size <= this.mJingleConnectionManager + .getAutoAcceptFileSize()) { + Log.d(Config.LOGTAG, "auto accepting file from " + + packet.getFrom()); + this.acceptedAutomatically = true; + this.sendAccept(); + } else { + message.markUnread(); + Log.d(Config.LOGTAG, + "not auto accepting new file offer with size: " + + size + + " allowed size:" + + this.mJingleConnectionManager + .getAutoAcceptFileSize()); + this.mXmppConnectionService.getNotificationService() + .push(message); + } + this.file = this.mXmppConnectionService.getFileBackend() + .getFile(message, false); + if (message.getEncryption() == Message.ENCRYPTION_OTR) { + byte[] key = conversation.getSymmetricKey(); + if (key == null) { + this.sendCancel(); + this.cancel(); + return; + } else { + this.file.setKey(key); + } + } + this.file.setExpectedSize(size); } else { this.sendCancel(); this.cancel(); @@ -354,7 +357,7 @@ public class JingleConnection implements Downloadable { this.mXmppConnectionService.markMessage(this.message, Message.STATUS_OFFERED); JinglePacket packet = this.bootstrapPacket("session-initiate"); Content content = new Content(this.contentCreator, this.contentName); - if (message.getType() == Message.TYPE_IMAGE) { + if (message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE) { content.setTransportId(this.transportId); this.file = this.mXmppConnectionService.getFileBackend().getFile( message, false); @@ -856,6 +859,14 @@ public class JingleConnection implements Downloadable { return null; } + public void updateProgress(int i) { + this.mProgress = i; + if (SystemClock.elapsedRealtime() - this.mLastGuiRefresh > 1000) { + this.mLastGuiRefresh = SystemClock.elapsedRealtime(); + mXmppConnectionService.updateConversationUi(); + } + } + interface OnProxyActivated { public void success(); @@ -900,4 +911,14 @@ public class JingleConnection implements Downloadable { return 0; } } + + @Override + public int getProgress() { + return this.mProgress; + } + + @Override + public String getMimeType() { + return this.file.getMimeType(); + } } diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java index 83b597eb5..8d0a188dc 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java @@ -15,6 +15,7 @@ import eu.siacs.conversations.utils.CryptoHelper; public class JingleSocks5Transport extends JingleTransport { private JingleCandidate candidate; + private JingleConnection connection; private String destination; private OutputStream outputStream; private InputStream inputStream; @@ -25,6 +26,7 @@ public class JingleSocks5Transport extends JingleTransport { public JingleSocks5Transport(JingleConnection jingleConnection, JingleCandidate candidate) { this.candidate = candidate; + this.connection = jingleConnection; try { MessageDigest mDigest = MessageDigest.getInstance("SHA-1"); StringBuilder destBuilder = new StringBuilder(); @@ -102,11 +104,15 @@ public class JingleSocks5Transport extends JingleTransport { callback.onFileTransferAborted(); return; } + long size = file.getSize(); + double transmitted = 0; int count; byte[] buffer = new byte[8192]; while ((count = fileInputStream.read(buffer)) > 0) { outputStream.write(buffer, 0, count); digest.update(buffer, 0, count); + transmitted += count; + connection.updateProgress((int) (((transmitted) / size) * 100)); } outputStream.flush(); file.setSha1Sum(CryptoHelper.bytesToHex(digest.digest())); @@ -151,6 +157,7 @@ public class JingleSocks5Transport extends JingleTransport { callback.onFileTransferAborted(); return; } + double size = file.getExpectedSize(); long remainingSize = file.getExpectedSize(); byte[] buffer = new byte[8192]; int count = buffer.length; @@ -164,6 +171,7 @@ public class JingleSocks5Transport extends JingleTransport { digest.update(buffer, 0, count); remainingSize -= count; } + connection.updateProgress((int) (((size - remainingSize) / size) * 100)); } fileOutputStream.flush(); fileOutputStream.close(); diff --git a/src/main/res/menu/attachment_choices.xml b/src/main/res/menu/attachment_choices.xml index 20932489d..12b37c08e 100644 --- a/src/main/res/menu/attachment_choices.xml +++ b/src/main/res/menu/attachment_choices.xml @@ -9,7 +9,6 @@ android:title="@string/attach_take_picture"/> + android:title="@string/choose_file"/> \ No newline at end of file diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 414de73bd..e51fbd186 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -58,7 +58,7 @@ Add contact delivery failed rejected - Receiving image file. Please wait… + Receiving image file (%1$d%%) Preparing image for transmission Clear history Clear Conversation History @@ -311,4 +311,8 @@ Scan QR code Show QR code Account details + Choose file + Receiving %1$s file (%2$d%%) + Download %s file + Open %s file From 02cbda68a7af5c500f2044cb97507c680ef2bc41 Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Thu, 13 Nov 2014 22:59:00 +0100 Subject: [PATCH 02/13] bug fixes and various improvements for file transfer --- .../siacs/conversations/http/HttpConnection.java | 8 +------- .../conversations/persistance/FileBackend.java | 15 +++++++++++++++ .../services/XmppConnectionService.java | 2 +- .../conversations/ui/adapter/MessageAdapter.java | 13 +++++++++---- .../xmpp/jingle/JingleConnection.java | 11 ++++------- 5 files changed, 30 insertions(+), 19 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/http/HttpConnection.java b/src/main/java/eu/siacs/conversations/http/HttpConnection.java index fd6b9c1a1..7ef813833 100644 --- a/src/main/java/eu/siacs/conversations/http/HttpConnection.java +++ b/src/main/java/eu/siacs/conversations/http/HttpConnection.java @@ -251,14 +251,8 @@ public class HttpConnection implements Downloadable { } private void updateImageBounds() { - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inJustDecodeBounds = true; - BitmapFactory.decodeFile(file.getAbsolutePath(), options); - int imageHeight = options.outHeight; - int imageWidth = options.outWidth; - message.setBody(mUrl.toString() + "|" + file.getSize() + '|' - + imageWidth + '|' + imageHeight); message.setType(Message.TYPE_IMAGE); + mXmppConnectionService.getFileBackend().updateFileParams(message); mXmppConnectionService.updateMessage(message); } diff --git a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java index f052bd532..2d054b5ec 100644 --- a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java @@ -433,6 +433,21 @@ public class FileBackend { return Uri.parse("file://" + file.getAbsolutePath()); } + public void updateFileParams(Message message) { + DownloadableFile file = getFile(message); + if (message.getType() == Message.TYPE_IMAGE || file.getMimeType().startsWith("image/")) { + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeFile(file.getAbsolutePath(), options); + int imageHeight = options.outHeight; + int imageWidth = options.outWidth; + message.setBody(Long.toString(file.getSize()) + '|' + imageWidth + '|' + imageHeight); + } else { + message.setBody(Long.toString(file.getSize())); + } + + } + public class FileCopyException extends Exception { private static final long serialVersionUID = -1010013599132881427L; private int resId; diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 36ccc6325..abcc92bec 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -311,6 +311,7 @@ public class XmppConnectionService extends Service { message.setType(Message.TYPE_FILE); message.setStatus(Message.STATUS_OFFERED); message.setRelativeFilePath(path); + getFileBackend().updateFileParams(message); return message; } return null; @@ -335,7 +336,6 @@ public class XmppConnectionService extends Service { public void run() { try { DownloadableFile file = getFileBackend().copyImageToPrivateStorage(message, uri); - message.setRelativeFilePath(file.getName()); if (conversation.getNextEncryption(forceEncryption()) == Message.ENCRYPTION_PGP) { getPgpEngine().encrypt(message, callback); } else { 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 6449a6f91..4d46f90e5 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -103,10 +103,11 @@ public class MessageAdapter extends ArrayAdapter { } boolean multiReceived = message.getConversation().getMode() == Conversation.MODE_MULTI && message.getMergedStatus() <= Message.STATUS_RECEIVED; - if (message.getType() == Message.TYPE_IMAGE - || message.getDownloadable() != null) { + if (message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE || message.getDownloadable() != null) { ImageParams params = message.getImageParams(); - if (params.size != 0) { + if (params.size > (1.5 * 1024 * 1024)) { + filesize = params.size / (1024 * 1024)+ " MB"; + } else if (params.size > 0) { filesize = params.size / 1024 + " KB"; } if (message.getDownloadable() != null && message.getDownloadable().getStatus() == Downloadable.STATUS_FAILED) { @@ -509,7 +510,11 @@ public class MessageAdapter extends ArrayAdapter { displayImageMessage(viewHolder, item); } } else if (item.getType() == Message.TYPE_FILE) { - displayOpenableMessage(viewHolder,item); + if (item.getImageParams().width > 0) { + displayImageMessage(viewHolder,item); + } else { + displayOpenableMessage(viewHolder, item); + } } else { if (item.getEncryption() == Message.ENCRYPTION_PGP) { if (activity.hasPgp()) { diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java index 3208cab4b..ade19c0ed 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java @@ -91,13 +91,7 @@ public class JingleConnection implements Downloadable { JingleConnection.this.mXmppConnectionService .getNotificationService().push(message); } - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inJustDecodeBounds = true; - BitmapFactory.decodeFile(file.getAbsolutePath(), options); - int imageHeight = options.outHeight; - int imageWidth = options.outWidth; - message.setBody(Long.toString(file.getSize()) + '|' - + imageWidth + '|' + imageHeight); + mXmppConnectionService.getFileBackend().updateFileParams(message); mXmppConnectionService.databaseBackend.createMessage(message); mXmppConnectionService.markMessage(message, Message.STATUS_RECEIVED); @@ -306,6 +300,9 @@ public class JingleConnection implements Downloadable { if (!fileNameElement.getContent().isEmpty()) { String parts[] = fileNameElement.getContent().split("/"); suffix = parts[parts.length - 1]; + if (message.getEncryption() == Message.ENCRYPTION_OTR && suffix.endsWith(".otr")) { + suffix = suffix.substring(0,suffix.length() - 4); + } } message.setRelativeFilePath(message.getUuid()+"_"+suffix); } From dac12be53e18962c80fd471421adac29b5c92f06 Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Fri, 14 Nov 2014 00:28:39 +0100 Subject: [PATCH 03/13] copy non local files to private storage first --- .../persistance/FileBackend.java | 32 ++++++++++++- .../services/XmppConnectionService.java | 45 ++++++++++++------- .../ui/ConversationActivity.java | 23 ++++++++-- 3 files changed, 77 insertions(+), 23 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java index 2d054b5ec..908cbefc1 100644 --- a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java @@ -29,6 +29,8 @@ import android.provider.MediaStore; import android.util.Base64; import android.util.Base64OutputStream; import android.util.Log; +import android.webkit.MimeTypeMap; + import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.DownloadableFile; @@ -118,8 +120,8 @@ public class FileBackend { public String getOriginalPath(Uri uri) { String path = null; if (uri.getScheme().equals("file")) { - path = uri.getPath(); - } else { + return uri.getPath(); + } else if (uri.toString().startsWith("content://media/")) { String[] projection = {MediaStore.MediaColumns.DATA}; Cursor metaCursor = mXmppConnectionService.getContentResolver().query(uri, projection, null, null, null); @@ -136,6 +138,32 @@ public class FileBackend { return path; } + public DownloadableFile copyFileToPrivateStorage(Message message, Uri uri) throws FileCopyException { + try { + Log.d(Config.LOGTAG, "copy " + uri.toString() + " to private storage"); + String mime = mXmppConnectionService.getContentResolver().getType(uri); + String extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(mime); + message.setRelativeFilePath(message.getUuid() + "." + extension); + DownloadableFile file = mXmppConnectionService.getFileBackend().getFile(message); + OutputStream os = new FileOutputStream(file); + InputStream is = mXmppConnectionService.getContentResolver().openInputStream(uri); + byte[] buffer = new byte[1024]; + int length; + while ((length = is.read(buffer)) > 0) { + os.write(buffer, 0, length); + } + os.flush(); + os.close(); + is.close(); + Log.d(Config.LOGTAG, "output file name " + mXmppConnectionService.getFileBackend().getFile(message)); + return file; + } catch (FileNotFoundException e) { + throw new FileCopyException(R.string.error_file_not_found); + } catch (IOException e) { + throw new FileCopyException(R.string.error_io_exception); + } + } + public DownloadableFile copyImageToPrivateStorage(Message message, Uri image) throws FileCopyException { return this.copyImageToPrivateStorage(message, image, 0); diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index abcc92bec..babcce266 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -295,29 +295,41 @@ public class XmppConnectionService extends Service { return this.mAvatarService; } - public Message attachFileToConversation(Conversation conversation, final Uri uri) { + public void attachFileToConversation(Conversation conversation, final Uri uri, final UiCallback callback) { + final Message message; + if (conversation.getNextEncryption(forceEncryption()) == Message.ENCRYPTION_PGP) { + message = new Message(conversation, "", + Message.ENCRYPTION_DECRYPTED); + } else { + message = new Message(conversation, "", + conversation.getNextEncryption(forceEncryption())); + } + message.setCounterpart(conversation.getNextCounterpart()); + message.setType(Message.TYPE_FILE); + message.setStatus(Message.STATUS_OFFERED); String path = getFileBackend().getOriginalPath(uri); if (path!=null) { - Log.d(Config.LOGTAG,"file path : "+path); - Message message; - if (conversation.getNextEncryption(forceEncryption()) == Message.ENCRYPTION_PGP) { - message = new Message(conversation, "", - Message.ENCRYPTION_DECRYPTED); - } else { - message = new Message(conversation, "", - conversation.getNextEncryption(forceEncryption())); - } - message.setCounterpart(conversation.getNextCounterpart()); - message.setType(Message.TYPE_FILE); - message.setStatus(Message.STATUS_OFFERED); message.setRelativeFilePath(path); getFileBackend().updateFileParams(message); - return message; + callback.success(message); + } else { + new Thread(new Runnable() { + @Override + public void run() { + try { + getFileBackend().copyFileToPrivateStorage(message, uri); + getFileBackend().updateFileParams(message); + callback.success(message); + } catch (FileBackend.FileCopyException e) { + callback.error(e.getResId(),message); + } + } + }).start(); + } - return null; } - public Message attachImageToConversation(final Conversation conversation, + public void attachImageToConversation(final Conversation conversation, final Uri uri, final UiCallback callback) { final Message message; if (conversation.getNextEncryption(forceEncryption()) == Message.ENCRYPTION_PGP) { @@ -346,7 +358,6 @@ public class XmppConnectionService extends Service { } } }).start(); - return message; } public Conversation find(Bookmark bookmark) { diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index 8c2f9dab4..9859d4249 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -315,7 +315,9 @@ public class ConversationActivity extends XmppActivity implements startActivityForResult(chooser, REQUEST_ATTACH_IMAGE_DIALOG); } else if (attachmentChoice == ATTACHMENT_CHOICE_CHOOSE_FILE) { Intent attachFileIntent = new Intent(); - attachFileIntent.setType("file/*"); + //attachFileIntent.setType("file/*"); + attachFileIntent.setType("*/*"); + attachFileIntent.addCategory(Intent.CATEGORY_OPENABLE); attachFileIntent.setAction(Intent.ACTION_GET_CONTENT); Intent chooser = Intent.createChooser(attachFileIntent, getString(R.string.attach_file)); @@ -780,9 +782,22 @@ public class ConversationActivity extends XmppActivity implements } private void attachFileToConversation(Conversation conversation, Uri uri) { - Log.d(Config.LOGTAG, "attachFileToConversation"); - Message message = xmppConnectionService.attachFileToConversation(conversation,uri); - xmppConnectionService.sendMessage(message); + xmppConnectionService.attachFileToConversation(conversation,uri, new UiCallback() { + @Override + public void success(Message message) { + xmppConnectionService.sendMessage(message); + } + + @Override + public void error(int errorCode, Message message) { + + } + + @Override + public void userInputRequried(PendingIntent pi, Message message) { + + } + }); } private void attachImageToConversation(Conversation conversation, Uri uri) { From c7acfe85c379b99c05cef98dbbab6f815b99ed83 Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Fri, 14 Nov 2014 01:29:56 +0100 Subject: [PATCH 04/13] progress for http images as well. fixed open button for sent files --- src/main/java/eu/siacs/conversations/Config.java | 1 + .../conversations/entities/Downloadable.java | 1 + .../siacs/conversations/http/HttpConnection.java | 15 +++++++++++++-- .../conversations/persistance/FileBackend.java | 11 ++++++++++- .../conversations/ui/adapter/MessageAdapter.java | 9 +++++++-- .../xmpp/jingle/JingleConnection.java | 8 ++++++-- src/main/res/values/strings.xml | 3 ++- 7 files changed, 40 insertions(+), 8 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java index 7dd5a7995..b1d915d24 100644 --- a/src/main/java/eu/siacs/conversations/Config.java +++ b/src/main/java/eu/siacs/conversations/Config.java @@ -19,6 +19,7 @@ public final class Config { public static final int MESSAGE_MERGE_WINDOW = 20; public static final boolean PARSE_EMOTICONS = false; + public static final int PROGRESS_UI_UPDATE_INTERVAL = 750; private Config() { diff --git a/src/main/java/eu/siacs/conversations/entities/Downloadable.java b/src/main/java/eu/siacs/conversations/entities/Downloadable.java index cc0dc157f..d3e863ef5 100644 --- a/src/main/java/eu/siacs/conversations/entities/Downloadable.java +++ b/src/main/java/eu/siacs/conversations/entities/Downloadable.java @@ -12,6 +12,7 @@ public interface Downloadable { public static final int STATUS_DOWNLOADING = 0x204; public static final int STATUS_DELETED = 0x205; public static final int STATUS_OFFER_CHECK_FILESIZE = 0x206; + public static final int STATUS_UPLOADING = 0x207; public boolean start(); diff --git a/src/main/java/eu/siacs/conversations/http/HttpConnection.java b/src/main/java/eu/siacs/conversations/http/HttpConnection.java index 7ef813833..68c26c474 100644 --- a/src/main/java/eu/siacs/conversations/http/HttpConnection.java +++ b/src/main/java/eu/siacs/conversations/http/HttpConnection.java @@ -3,6 +3,7 @@ package eu.siacs.conversations.http; import android.content.Intent; import android.graphics.BitmapFactory; import android.net.Uri; +import android.os.SystemClock; import org.apache.http.conn.ssl.StrictHostnameVerifier; @@ -21,6 +22,7 @@ import javax.net.ssl.SSLContext; import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.X509TrustManager; +import eu.siacs.conversations.Config; import eu.siacs.conversations.entities.Downloadable; import eu.siacs.conversations.entities.DownloadableFile; import eu.siacs.conversations.entities.Message; @@ -38,6 +40,7 @@ public class HttpConnection implements Downloadable { private int mStatus = Downloadable.STATUS_UNKNOWN; private boolean acceptedAutomatically = false; private int mProgress = 0; + private long mLastGuiRefresh = 0; public HttpConnection(HttpConnectionManager manager) { this.mHttpConnectionManager = manager; @@ -243,7 +246,7 @@ public class HttpConnection implements Downloadable { while ((count = is.read(buffer)) != -1) { transmitted += count; os.write(buffer, 0, count); - mProgress = (int) (expected * 100 / transmitted); + updateProgress((int) ((((double) transmitted) / expected) * 100)); } os.flush(); os.close(); @@ -252,12 +255,20 @@ public class HttpConnection implements Downloadable { private void updateImageBounds() { message.setType(Message.TYPE_IMAGE); - mXmppConnectionService.getFileBackend().updateFileParams(message); + mXmppConnectionService.getFileBackend().updateFileParams(message,mUrl); mXmppConnectionService.updateMessage(message); } } + public void updateProgress(int i) { + this.mProgress = i; + if (SystemClock.elapsedRealtime() - this.mLastGuiRefresh > Config.PROGRESS_UI_UPDATE_INTERVAL) { + this.mLastGuiRefresh = SystemClock.elapsedRealtime(); + mXmppConnectionService.updateConversationUi(); + } + } + @Override public int getStatus() { return this.mStatus; diff --git a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java index 908cbefc1..7b0ae1807 100644 --- a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java @@ -8,6 +8,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.net.URL; import java.net.URLConnection; import java.security.DigestOutputStream; import java.security.MessageDigest; @@ -462,6 +463,10 @@ public class FileBackend { } public void updateFileParams(Message message) { + updateFileParams(message,null); + } + + public void updateFileParams(Message message, URL url) { DownloadableFile file = getFile(message); if (message.getType() == Message.TYPE_IMAGE || file.getMimeType().startsWith("image/")) { BitmapFactory.Options options = new BitmapFactory.Options(); @@ -469,7 +474,11 @@ public class FileBackend { BitmapFactory.decodeFile(file.getAbsolutePath(), options); int imageHeight = options.outHeight; int imageWidth = options.outWidth; - message.setBody(Long.toString(file.getSize()) + '|' + imageWidth + '|' + imageHeight); + if (url == null) { + message.setBody(Long.toString(file.getSize()) + '|' + imageWidth + '|' + imageHeight); + } else { + message.setBody(url.toString()+"|"+Long.toString(file.getSize()) + '|' + imageWidth + '|' + imageHeight); + } } else { message.setBody(Long.toString(file.getSize())); } 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 4d46f90e5..81eccacce 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -119,7 +119,12 @@ public class MessageAdapter extends ArrayAdapter { info = getContext().getString(R.string.waiting); break; case Message.STATUS_UNSEND: - info = getContext().getString(R.string.sending); + Downloadable d = message.getDownloadable(); + if (d!=null) { + info = getContext().getString(R.string.sending_file,d.getProgress()); + } else { + info = getContext().getString(R.string.sending); + } break; case Message.STATUS_OFFERED: info = getContext().getString(R.string.offering); @@ -478,7 +483,7 @@ public class MessageAdapter extends ArrayAdapter { }); } - if (item.getDownloadable() != null) { + if (item.getDownloadable() != null && item.getDownloadable().getStatus() != Downloadable.STATUS_UPLOADING) { Downloadable d = item.getDownloadable(); if (d.getStatus() == Downloadable.STATUS_DOWNLOADING) { if (item.getType() == Message.TYPE_FILE) { diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java index ade19c0ed..f42e89a99 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java @@ -44,7 +44,7 @@ public class JingleConnection implements Downloadable { private int ibbBlockSize = 4096; private int mJingleStatus = -1; - private int mStatus = -1; + private int mStatus = Downloadable.STATUS_UNKNOWN; private Message message; private String sessionId; private Account account; @@ -95,6 +95,8 @@ public class JingleConnection implements Downloadable { mXmppConnectionService.databaseBackend.createMessage(message); mXmppConnectionService.markMessage(message, Message.STATUS_RECEIVED); + } else { + message.setDownloadable(null); } Log.d(Config.LOGTAG, "sucessfully transmitted file:" + file.getAbsolutePath()); @@ -198,6 +200,8 @@ public class JingleConnection implements Downloadable { this.contentCreator = "initiator"; this.contentName = this.mJingleConnectionManager.nextRandomId(); this.message = message; + this.message.setDownloadable(this); + this.mStatus = Downloadable.STATUS_UPLOADING; this.account = message.getConversation().getAccount(); this.initiator = this.account.getJid(); this.responder = this.message.getCounterpart(); @@ -858,7 +862,7 @@ public class JingleConnection implements Downloadable { public void updateProgress(int i) { this.mProgress = i; - if (SystemClock.elapsedRealtime() - this.mLastGuiRefresh > 1000) { + if (SystemClock.elapsedRealtime() - this.mLastGuiRefresh > Config.PROGRESS_UI_UPDATE_INTERVAL) { this.mLastGuiRefresh = SystemClock.elapsedRealtime(); mXmppConnectionService.updateConversationUi(); } diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index e51fbd186..43552aef3 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -312,7 +312,8 @@ Show QR code Account details Choose file - Receiving %1$s file (%2$d%%) + Receiving %1$s file (%2$d%% completed) Download %s file Open %s file + sending (%1$d%% completed) From 16847a30c88246381a026bce9f2435be2bd77422 Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Fri, 14 Nov 2014 03:27:18 +0100 Subject: [PATCH 05/13] support for pgp files --- .../java/eu/siacs/conversations/Config.java | 2 +- .../siacs/conversations/crypto/PgpEngine.java | 6 ++- .../persistance/FileBackend.java | 37 ++++++++++--------- .../services/XmppConnectionService.java | 14 +++++-- .../xmpp/jingle/JingleConnection.java | 2 + 5 files changed, 38 insertions(+), 23 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java index b1d915d24..a40cff916 100644 --- a/src/main/java/eu/siacs/conversations/Config.java +++ b/src/main/java/eu/siacs/conversations/Config.java @@ -19,7 +19,7 @@ public final class Config { public static final int MESSAGE_MERGE_WINDOW = 20; public static final boolean PARSE_EMOTICONS = false; - public static final int PROGRESS_UI_UPDATE_INTERVAL = 750; + public static final int PROGRESS_UI_UPDATE_INTERVAL = 750; private Config() { diff --git a/src/main/java/eu/siacs/conversations/crypto/PgpEngine.java b/src/main/java/eu/siacs/conversations/crypto/PgpEngine.java index 3d7cc6715..3f84daf66 100644 --- a/src/main/java/eu/siacs/conversations/crypto/PgpEngine.java +++ b/src/main/java/eu/siacs/conversations/crypto/PgpEngine.java @@ -80,12 +80,13 @@ public class PgpEngine { } } }); - } else if (message.getType() == Message.TYPE_IMAGE) { + } else if (message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE) { try { final DownloadableFile inputFile = this.mXmppConnectionService .getFileBackend().getFile(message, false); final DownloadableFile outputFile = this.mXmppConnectionService .getFileBackend().getFile(message, true); + outputFile.getParentFile().mkdirs(); outputFile.createNewFile(); InputStream is = new FileInputStream(inputFile); OutputStream os = new FileOutputStream(outputFile); @@ -199,12 +200,13 @@ public class PgpEngine { } } }); - } else if (message.getType() == Message.TYPE_IMAGE) { + } else if (message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE) { try { DownloadableFile inputFile = this.mXmppConnectionService .getFileBackend().getFile(message, true); DownloadableFile outputFile = this.mXmppConnectionService .getFileBackend().getFile(message, false); + outputFile.getParentFile().mkdirs(); outputFile.createNewFile(); InputStream is = new FileInputStream(inputFile); OutputStream os = new FileOutputStream(outputFile); diff --git a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java index 7b0ae1807..3d771572a 100644 --- a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java @@ -2,14 +2,12 @@ package eu.siacs.conversations.persistance; import java.io.ByteArrayOutputStream; import java.io.File; -import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URL; -import java.net.URLConnection; import java.security.DigestOutputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -17,7 +15,6 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; -import android.content.ContentResolver; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; @@ -60,30 +57,36 @@ public class FileBackend { public DownloadableFile getFile(Message message, boolean decrypted) { String path = message.getRelativeFilePath(); - if (path != null && !path.isEmpty()) { + if (!decrypted && (message.getEncryption() == Message.ENCRYPTION_PGP || message.getEncryption() == Message.ENCRYPTION_DECRYPTED)) { + String extension; + if (path != null && !path.isEmpty()) { + String[] parts = path.split("\\."); + extension = "."+parts[parts.length - 1]; + } else if (message.getType() == Message.TYPE_IMAGE) { + extension = ".webp"; + } else { + extension = ""; + } + return new DownloadableFile(getConversationsFileDirectory()+message.getUuid()+extension+".pgp"); + } else if (path != null && !path.isEmpty()) { if (path.startsWith("/")) { return new DownloadableFile(path); } else { - return new DownloadableFile(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)+"/"+path); + return new DownloadableFile(getConversationsFileDirectory()+path); } } else { StringBuilder filename = new StringBuilder(); - filename.append(getConversationsDirectory()); - filename.append(message.getUuid()); - if ((decrypted) || (message.getEncryption() == Message.ENCRYPTION_NONE)) { - filename.append(".webp"); - } else { - if (message.getEncryption() == Message.ENCRYPTION_OTR) { - filename.append(".webp"); - } else { - filename.append(".webp.pgp"); - } - } + filename.append(getConversationsImageDirectory()); + filename.append(message.getUuid()+".webp"); return new DownloadableFile(filename.toString()); } } - public static String getConversationsDirectory() { + public static String getConversationsFileDirectory() { + return Environment.getExternalStorageDirectory().getAbsolutePath()+"/Conversations/"; + } + + public static String getConversationsImageDirectory() { return Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES).getAbsolutePath() + "/Conversations/"; diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index babcce266..4565ce30f 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -211,7 +211,7 @@ public class XmppConnectionService extends Service { private Integer rosterChangedListenerCount = 0; private SecureRandom mRandom; private FileObserver fileObserver = new FileObserver( - FileBackend.getConversationsDirectory()) { + FileBackend.getConversationsImageDirectory()) { @Override public void onEvent(int event, String path) { @@ -311,7 +311,11 @@ public class XmppConnectionService extends Service { if (path!=null) { message.setRelativeFilePath(path); getFileBackend().updateFileParams(message); - callback.success(message); + if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) { + getPgpEngine().encrypt(message, callback); + } else { + callback.success(message); + } } else { new Thread(new Runnable() { @Override @@ -319,7 +323,11 @@ public class XmppConnectionService extends Service { try { getFileBackend().copyFileToPrivateStorage(message, uri); getFileBackend().updateFileParams(message); - callback.success(message); + if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) { + getPgpEngine().encrypt(message, callback); + } else { + callback.success(message); + } } catch (FileBackend.FileCopyException e) { callback.error(e.getResId(),message); } diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java index f42e89a99..793c6c54d 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java @@ -306,6 +306,8 @@ public class JingleConnection implements Downloadable { suffix = parts[parts.length - 1]; if (message.getEncryption() == Message.ENCRYPTION_OTR && suffix.endsWith(".otr")) { suffix = suffix.substring(0,suffix.length() - 4); + } else if (message.getEncryption() == Message.ENCRYPTION_PGP && (suffix.endsWith(".pgp") || suffix.endsWith(".gpg"))) { + suffix = suffix.substring(0,suffix.length() - 4); } } message.setRelativeFilePath(message.getUuid()+"_"+suffix); From e7a70a46e0154740177dcdea7fad255dcd4067e9 Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Fri, 14 Nov 2014 12:31:57 +0100 Subject: [PATCH 06/13] some mime and pgp fixes for file transfer --- .../siacs/conversations/crypto/PgpEngine.java | 21 +------ .../entities/DownloadableFile.java | 14 +++-- .../persistance/FileBackend.java | 2 +- .../ui/ConversationActivity.java | 24 ++++---- .../ui/adapter/MessageAdapter.java | 61 ++++++++----------- .../xmpp/jingle/JingleConnection.java | 21 ++++++- src/main/res/values/strings.xml | 1 + 7 files changed, 71 insertions(+), 73 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/crypto/PgpEngine.java b/src/main/java/eu/siacs/conversations/crypto/PgpEngine.java index 3f84daf66..83d9b7b2e 100644 --- a/src/main/java/eu/siacs/conversations/crypto/PgpEngine.java +++ b/src/main/java/eu/siacs/conversations/crypto/PgpEngine.java @@ -3,7 +3,6 @@ package eu.siacs.conversations.crypto; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; @@ -24,7 +23,6 @@ import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.ui.UiCallback; import android.app.PendingIntent; import android.content.Intent; -import android.graphics.BitmapFactory; import android.net.Uri; public class PgpEngine { @@ -98,24 +96,7 @@ public class PgpEngine { OpenPgpApi.RESULT_CODE_ERROR)) { case OpenPgpApi.RESULT_CODE_SUCCESS: URL url = message.getImageParams().url; - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inJustDecodeBounds = true; - BitmapFactory.decodeFile( - outputFile.getAbsolutePath(), options); - int imageHeight = options.outHeight; - int imageWidth = options.outWidth; - if (url == null) { - message.setBody(Long.toString(outputFile - .getSize()) - + '|' - + imageWidth - + '|' - + imageHeight); - } else { - message.setBody(url.toString() + "|" - + Long.toString(outputFile.getSize()) - + '|' + imageWidth + '|' + imageHeight); - } + mXmppConnectionService.getFileBackend().updateFileParams(message,url); message.setEncryption(Message.ENCRYPTION_DECRYPTED); PgpEngine.this.mXmppConnectionService .updateMessage(message); diff --git a/src/main/java/eu/siacs/conversations/entities/DownloadableFile.java b/src/main/java/eu/siacs/conversations/entities/DownloadableFile.java index 6aff643a0..25f339071 100644 --- a/src/main/java/eu/siacs/conversations/entities/DownloadableFile.java +++ b/src/main/java/eu/siacs/conversations/entities/DownloadableFile.java @@ -55,13 +55,15 @@ public class DownloadableFile extends File { } public String getMimeType() { - if (mime==null) { - mime = URLConnection.guessContentTypeFromName(this.getAbsolutePath()); - if (mime == null) { - mime = ""; - } + String path = this.getAbsolutePath(); + String mime = URLConnection.guessContentTypeFromName(path); + if (mime != null) { + return mime; + } else if (mime == null && path.endsWith(".webp")) { + return "image/webp"; + } else { + return ""; } - return mime; } public void setExpectedSize(long size) { diff --git a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java index 3d771572a..9683d38d2 100644 --- a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java @@ -62,7 +62,7 @@ public class FileBackend { if (path != null && !path.isEmpty()) { String[] parts = path.split("\\."); extension = "."+parts[parts.length - 1]; - } else if (message.getType() == Message.TYPE_IMAGE) { + } else if (message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_TEXT) { extension = ".webp"; } else { extension = ""; diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index 9859d4249..7e28cc6c3 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -15,7 +15,6 @@ import android.os.SystemClock; import android.provider.MediaStore; import android.support.v4.widget.SlidingPaneLayout; import android.support.v4.widget.SlidingPaneLayout.PanelSlideListener; -import android.util.Log; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; @@ -32,7 +31,6 @@ import android.widget.Toast; import java.util.ArrayList; import java.util.List; -import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; @@ -80,7 +78,7 @@ public class ConversationActivity extends XmppActivity implements private ArrayAdapter listAdapter; - private Toast prepareImageToast; + private Toast prepareFileToast; public List getConversationList() { @@ -782,15 +780,19 @@ public class ConversationActivity extends XmppActivity implements } private void attachFileToConversation(Conversation conversation, Uri uri) { + prepareFileToast = Toast.makeText(getApplicationContext(), + getText(R.string.preparing_file), Toast.LENGTH_LONG); + prepareFileToast.show(); xmppConnectionService.attachFileToConversation(conversation,uri, new UiCallback() { @Override public void success(Message message) { + hidePrepareFileToast(); xmppConnectionService.sendMessage(message); } @Override public void error(int errorCode, Message message) { - + displayErrorDialog(errorCode); } @Override @@ -801,16 +803,16 @@ public class ConversationActivity extends XmppActivity implements } private void attachImageToConversation(Conversation conversation, Uri uri) { - prepareImageToast = Toast.makeText(getApplicationContext(), + prepareFileToast = Toast.makeText(getApplicationContext(), getText(R.string.preparing_image), Toast.LENGTH_LONG); - prepareImageToast.show(); + prepareFileToast.show(); xmppConnectionService.attachImageToConversation(conversation, uri, new UiCallback() { @Override public void userInputRequried(PendingIntent pi, Message object) { - hidePrepareImageToast(); + hidePrepareFileToast(); ConversationActivity.this.runIntent(pi, ConversationActivity.REQUEST_SEND_PGP_IMAGE); } @@ -822,19 +824,19 @@ public class ConversationActivity extends XmppActivity implements @Override public void error(int error, Message message) { - hidePrepareImageToast(); + hidePrepareFileToast(); displayErrorDialog(error); } }); } - private void hidePrepareImageToast() { - if (prepareImageToast != null) { + private void hidePrepareFileToast() { + if (prepareFileToast != null) { runOnUiThread(new Runnable() { @Override public void run() { - prepareImageToast.cancel(); + prepareFileToast.cancel(); } }); } 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 81eccacce..71795e986 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -281,15 +281,16 @@ public class MessageAdapter extends ArrayAdapter { } private void displayOpenableMessage(ViewHolder viewHolder,final Message message) { + final DownloadableFile file = activity.xmppConnectionService.getFileBackend().getFile(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_file,activity.xmppConnectionService.getFileBackend().getFile(message).getMimeType())); + viewHolder.download_button.setText(activity.getString(R.string.open_file,file.getMimeType())); viewHolder.download_button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - openDonwloadable(message); + openDonwloadable(file); } }); viewHolder.download_button.setOnLongClickListener(openContextMenu); @@ -506,43 +507,35 @@ public class MessageAdapter extends ArrayAdapter { } else if (d.getStatus() == Downloadable.STATUS_FAILED) { displayInfoMessage(viewHolder, activity.getString(R.string.image_transmission_failed)); } - } else if (item.getType() == Message.TYPE_IMAGE) { - if (item.getEncryption() == Message.ENCRYPTION_PGP) { - displayInfoMessage(viewHolder,activity.getString(R.string.encrypted_message)); - } else if (item.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) { - displayDecryptionFailed(viewHolder); - } else { - displayImageMessage(viewHolder, item); - } - } else if (item.getType() == Message.TYPE_FILE) { + } else if (item.getType() == Message.TYPE_IMAGE && item.getEncryption() != Message.ENCRYPTION_PGP && item.getEncryption() != Message.ENCRYPTION_DECRYPTION_FAILED) { + displayImageMessage(viewHolder, item); + } else if (item.getType() == Message.TYPE_FILE && item.getEncryption() != Message.ENCRYPTION_PGP && item.getEncryption() != Message.ENCRYPTION_DECRYPTION_FAILED) { if (item.getImageParams().width > 0) { displayImageMessage(viewHolder,item); } else { displayOpenableMessage(viewHolder, item); } - } else { - if (item.getEncryption() == Message.ENCRYPTION_PGP) { - if (activity.hasPgp()) { - displayInfoMessage(viewHolder,activity.getString(R.string.encrypted_message)); - } else { - displayInfoMessage(viewHolder, - activity.getString(R.string.install_openkeychain)); - if (viewHolder != null) { - viewHolder.message_box - .setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - activity.showInstallPgpDialog(); - } - }); - } - } - } else if (item.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) { - displayDecryptionFailed(viewHolder); + } else if (item.getEncryption() == Message.ENCRYPTION_PGP) { + if (activity.hasPgp()) { + displayInfoMessage(viewHolder,activity.getString(R.string.encrypted_message)); } else { - displayTextMessage(viewHolder, item); + displayInfoMessage(viewHolder, + activity.getString(R.string.install_openkeychain)); + if (viewHolder != null) { + viewHolder.message_box + .setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + activity.showInstallPgpDialog(); + } + }); + } } + } else if (item.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) { + displayDecryptionFailed(viewHolder); + } else { + displayTextMessage(viewHolder, item); } displayStatus(viewHolder, item); @@ -560,8 +553,8 @@ public class MessageAdapter extends ArrayAdapter { } } - public void openDonwloadable(Message message) { - DownloadableFile file = activity.xmppConnectionService.getFileBackend().getFile(message); + public void openDonwloadable(DownloadableFile file) { + Log.d(Config.LOGTAG,"file "+file.getAbsolutePath()); Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(file), file.getMimeType()); getContext().startActivity(intent); diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java index 793c6c54d..0c79d101d 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java @@ -1,5 +1,6 @@ package eu.siacs.conversations.xmpp.jingle; +import java.net.URLConnection; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; @@ -97,6 +98,9 @@ public class JingleConnection implements Downloadable { Message.STATUS_RECEIVED); } else { message.setDownloadable(null); + if (message.getEncryption() != Message.ENCRYPTION_PGP) { + file.delete(); + } } Log.d(Config.LOGTAG, "sucessfully transmitted file:" + file.getAbsolutePath()); @@ -922,6 +926,21 @@ public class JingleConnection implements Downloadable { @Override public String getMimeType() { - return this.file.getMimeType(); + if (this.message.getType() == Message.TYPE_FILE) { + String mime = null; + String path = this.message.getRelativeFilePath(); + if (path != null && !this.message.getRelativeFilePath().isEmpty()) { + mime = URLConnection.guessContentTypeFromName(this.message.getRelativeFilePath()); + if (mime!=null) { + return mime; + } else { + return ""; + } + } else { + return ""; + } + } else { + return "image/webp"; + } } } diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 43552aef3..c37566735 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -316,4 +316,5 @@ Download %s file Open %s file sending (%1$d%% completed) + Preparing file for transmission From af2922adeac1b5dd6e4f30e930ad54171b5511a9 Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Fri, 14 Nov 2014 14:04:34 +0100 Subject: [PATCH 07/13] progress for ibb transfers --- .../java/eu/siacs/conversations/Config.java | 2 ++ .../xmpp/jingle/JingleConnection.java | 8 +++---- .../xmpp/jingle/JingleConnectionManager.java | 4 ++++ .../xmpp/jingle/JingleInbandTransport.java | 22 ++++++++++++++----- .../xmpp/jingle/JingleSocks5Transport.java | 4 ++-- 5 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java index a40cff916..7af29451f 100644 --- a/src/main/java/eu/siacs/conversations/Config.java +++ b/src/main/java/eu/siacs/conversations/Config.java @@ -21,6 +21,8 @@ public final class Config { public static final boolean PARSE_EMOTICONS = false; public static final int PROGRESS_UI_UPDATE_INTERVAL = 750; + public static final boolean NO_PROXY_LOOKUP = false; //useful to debug ibb + private Config() { } diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java index 0c79d101d..9a7e16f97 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java @@ -98,7 +98,7 @@ public class JingleConnection implements Downloadable { Message.STATUS_RECEIVED); } else { message.setDownloadable(null); - if (message.getEncryption() != Message.ENCRYPTION_PGP) { + if (message.getEncryption() == Message.ENCRYPTION_PGP || message.getEncryption() == Message.ENCRYPTION_DECRYPTED) { file.delete(); } } @@ -664,8 +664,7 @@ public class JingleConnection implements Downloadable { } } this.transportId = packet.getJingleContent().getTransportId(); - this.transport = new JingleInbandTransport(this.account, - this.responder, this.transportId, this.ibbBlockSize); + this.transport = new JingleInbandTransport(this, this.transportId, this.ibbBlockSize); this.transport.receive(file, onFileTransmissionSatusChanged); JinglePacket answer = bootstrapPacket("transport-accept"); Content content = new Content("initiator", "a-file-offer"); @@ -687,8 +686,7 @@ public class JingleConnection implements Downloadable { this.ibbBlockSize = bs; } } - this.transport = new JingleInbandTransport(this.account, - this.responder, this.transportId, this.ibbBlockSize); + this.transport = new JingleInbandTransport(this, this.transportId, this.ibbBlockSize); this.transport.connect(new OnTransportConnected() { @Override diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java index 05a658be2..72c960d84 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java @@ -75,6 +75,10 @@ public class JingleConnectionManager extends AbstractConnectionManager { public void getPrimaryCandidate(Account account, final OnPrimaryCandidateFound listener) { + if (Config.NO_PROXY_LOOKUP) { + listener.onPrimaryCandidateFound(false, null); + return; + } if (!this.primaryCandidates.containsKey(account.getJid().toBareJid())) { String xmlns = "http://jabber.org/protocol/bytestreams"; final String proxy = account.getXmppConnection() diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java index e3f4fd619..791f48600 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java @@ -8,6 +8,7 @@ import java.security.NoSuchAlgorithmException; import java.util.Arrays; import android.util.Base64; + import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.DownloadableFile; import eu.siacs.conversations.utils.CryptoHelper; @@ -28,10 +29,12 @@ public class JingleInbandTransport extends JingleTransport { private boolean established = false; private DownloadableFile file; + private JingleConnection connection; private InputStream fileInputStream = null; private OutputStream fileOutputStream; - private long remainingSize; + private long remainingSize = 0; + private long fileSize = 0; private MessageDigest digest; private OnFileTransmissionStatusChanged onFileTransmissionStatusChanged; @@ -45,10 +48,10 @@ public class JingleInbandTransport extends JingleTransport { } }; - public JingleInbandTransport(final Account account, final Jid counterpart, - final String sid, final int blocksize) { - this.account = account; - this.counterpart = counterpart; + public JingleInbandTransport(final JingleConnection connection, final String sid, final int blocksize) { + this.connection = connection; + this.account = connection.getAccount(); + this.counterpart = connection.getCounterPart(); this.blockSize = blocksize; this.bufferSize = blocksize / 4; this.sessionId = sid; @@ -92,7 +95,7 @@ public class JingleInbandTransport extends JingleTransport { callback.onFileTransferAborted(); return; } - this.remainingSize = file.getExpectedSize(); + this.remainingSize = this.fileSize = file.getExpectedSize(); } catch (final NoSuchAlgorithmException | IOException e) { callback.onFileTransferAborted(); } @@ -104,6 +107,8 @@ public class JingleInbandTransport extends JingleTransport { this.onFileTransmissionStatusChanged = callback; this.file = file; try { + this.remainingSize = this.file.getSize(); + this.fileSize = this.remainingSize; this.digest = MessageDigest.getInstance("SHA-1"); this.digest.reset(); fileInputStream = this.file.createInputStream(); @@ -126,6 +131,7 @@ public class JingleInbandTransport extends JingleTransport { fileInputStream.close(); this.onFileTransmissionStatusChanged.onFileTransmitted(file); } else { + this.remainingSize -= count; this.digest.update(buffer); String base64 = Base64.encodeToString(buffer, Base64.NO_WRAP); IqPacket iq = new IqPacket(IqPacket.TYPE_SET); @@ -140,6 +146,7 @@ public class JingleInbandTransport extends JingleTransport { this.account.getXmppConnection().sendIqPacket(iq, this.onAckReceived); this.seq++; + connection.updateProgress((int) ((((double) (this.fileSize - this.remainingSize)) / this.fileSize) * 100)); } } catch (IOException e) { this.onFileTransmissionStatusChanged.onFileTransferAborted(); @@ -155,6 +162,7 @@ public class JingleInbandTransport extends JingleTransport { } this.remainingSize -= buffer.length; + this.fileOutputStream.write(buffer); this.digest.update(buffer); @@ -163,6 +171,8 @@ public class JingleInbandTransport extends JingleTransport { fileOutputStream.flush(); fileOutputStream.close(); this.onFileTransmissionStatusChanged.onFileTransmitted(file); + } else { + connection.updateProgress((int) ((((double) (this.fileSize - this.remainingSize)) / this.fileSize) * 100)); } } catch (IOException e) { this.onFileTransmissionStatusChanged.onFileTransferAborted(); diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java index 8d0a188dc..1ed3fa115 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java @@ -105,14 +105,14 @@ public class JingleSocks5Transport extends JingleTransport { return; } long size = file.getSize(); - double transmitted = 0; + long transmitted = 0; int count; byte[] buffer = new byte[8192]; while ((count = fileInputStream.read(buffer)) > 0) { outputStream.write(buffer, 0, count); digest.update(buffer, 0, count); transmitted += count; - connection.updateProgress((int) (((transmitted) / size) * 100)); + connection.updateProgress((int) ((((double) transmitted) / size) * 100)); } outputStream.flush(); file.setSha1Sum(CryptoHelper.bytesToHex(digest.digest())); From 4ab558715cc279515894d8ad28053716d3d61ad2 Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Fri, 14 Nov 2014 17:39:03 +0100 Subject: [PATCH 08/13] adepted conversationadapter to deal with files --- .../ui/adapter/ConversationAdapter.java | 24 ++++++++++++++++--- src/main/res/values/strings.xml | 2 ++ 2 files changed, 23 insertions(+), 3 deletions(-) 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 b3df8d72b..b1aea2094 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java @@ -6,6 +6,7 @@ import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Downloadable; +import eu.siacs.conversations.entities.DownloadableFile; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.ui.ConversationActivity; import eu.siacs.conversations.ui.XmppActivity; @@ -75,7 +76,7 @@ public class ConversationAdapter extends ArrayAdapter { convName.setTypeface(null, Typeface.NORMAL); } - if (message.getType() == Message.TYPE_IMAGE + if (message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE || message.getDownloadable() != null) { Downloadable d = message.getDownloadable(); if (conversation.isRead()) { @@ -89,13 +90,25 @@ public class ConversationAdapter extends ArrayAdapter { if (d.getStatus() == Downloadable.STATUS_CHECKING) { mLastMessage.setText(R.string.checking_image); } else if (d.getStatus() == Downloadable.STATUS_DOWNLOADING) { - mLastMessage.setText(R.string.receiving_image); + if (message.getType() == Message.TYPE_FILE) { + mLastMessage.setText(getContext().getString(R.string.receiving_file,d.getMimeType(), d.getProgress())); + } else { + mLastMessage.setText(getContext().getString(R.string.receiving_image, d.getProgress())); + } } else if (d.getStatus() == Downloadable.STATUS_OFFER) { - mLastMessage.setText(R.string.image_offered_for_download); + if (message.getType() == Message.TYPE_FILE) { + mLastMessage.setText(R.string.file_offered_for_download); + } else { + mLastMessage.setText(R.string.image_offered_for_download); + } } else if (d.getStatus() == Downloadable.STATUS_OFFER_CHECK_FILESIZE) { mLastMessage.setText(R.string.image_offered_for_download); } else if (d.getStatus() == Downloadable.STATUS_DELETED) { mLastMessage.setText(R.string.image_file_deleted); + } else if (message.getImageParams().width > 0) { + mLastMessage.setVisibility(View.GONE); + imagePreview.setVisibility(View.VISIBLE); + activity.loadBitmap(message, imagePreview); } else { mLastMessage.setText(""); } @@ -103,6 +116,11 @@ public class ConversationAdapter extends ArrayAdapter { imagePreview.setVisibility(View.GONE); mLastMessage.setVisibility(View.VISIBLE); mLastMessage.setText(R.string.encrypted_message_received); + } else if (message.getType() == Message.TYPE_FILE && message.getImageParams().width <= 0) { + DownloadableFile file = activity.xmppConnectionService.getFileBackend().getFile(message); + mLastMessage.setVisibility(View.VISIBLE); + imagePreview.setVisibility(View.GONE); + mLastMessage.setText(getContext().getString(R.string.file,file.getMimeType())); } else { mLastMessage.setVisibility(View.GONE); imagePreview.setVisibility(View.VISIBLE); diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index c37566735..3b030e16c 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -317,4 +317,6 @@ Open %s file sending (%1$d%% completed) Preparing file for transmission + File offered for download + %s file; From cc4f3702a83b5f4d4d57aa66bf50c5ba3b96e72b Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Sat, 15 Nov 2014 12:37:09 +0100 Subject: [PATCH 09/13] made file transfers cancelable --- .../conversations/entities/Downloadable.java | 2 + .../services/XmppConnectionService.java | 5 ++ .../ui/ConversationFragment.java | 17 ++++++- .../xmpp/jingle/JingleConnection.java | 48 ++++++++++++------- .../xmpp/jingle/JingleInbandTransport.java | 18 +++++-- .../xmpp/jingle/JingleTransport.java | 2 + src/main/res/menu/message_context.xml | 3 ++ src/main/res/values/strings.xml | 3 +- 8 files changed, 76 insertions(+), 22 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/entities/Downloadable.java b/src/main/java/eu/siacs/conversations/entities/Downloadable.java index d3e863ef5..d25bf93a8 100644 --- a/src/main/java/eu/siacs/conversations/entities/Downloadable.java +++ b/src/main/java/eu/siacs/conversations/entities/Downloadable.java @@ -23,4 +23,6 @@ public interface Downloadable { public int getProgress(); public String getMimeType(); + + public void cancel(); } diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 4565ce30f..06137c642 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -2040,5 +2040,10 @@ public class XmppConnectionService extends Service { return ""; } + @Override + public void cancel() { + + } + } } diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index 63d740c32..e15a6bbc7 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -43,6 +43,7 @@ import eu.siacs.conversations.crypto.PgpEngine; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; +import eu.siacs.conversations.entities.Downloadable; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.MucOptions; import eu.siacs.conversations.entities.Presences; @@ -343,6 +344,7 @@ public class ConversationFragment extends Fragment { MenuItem sendAgain = menu.findItem(R.id.send_again); MenuItem copyUrl = menu.findItem(R.id.copy_url); MenuItem downloadImage = menu.findItem(R.id.download_image); + MenuItem cancelTransmission = menu.findItem(R.id.cancel_transmission); if (this.selectedMessage.getType() != Message.TYPE_TEXT || this.selectedMessage.getDownloadable() != null) { copyText.setVisible(false); @@ -359,12 +361,15 @@ public class ConversationFragment extends Fragment { || this.selectedMessage.getImageParams().url == null) { copyUrl.setVisible(false); } - if (this.selectedMessage.getType() != Message.TYPE_TEXT || this.selectedMessage.getDownloadable() != null || !this.selectedMessage.bodyContainsDownloadable()) { downloadImage.setVisible(false); } + if (this.selectedMessage.getDownloadable() == null + || this.selectedMessage.getDownloadable().getStatus() == Downloadable.STATUS_DELETED) { + cancelTransmission.setVisible(false); + } } } @@ -386,6 +391,9 @@ public class ConversationFragment extends Fragment { case R.id.download_image: downloadImage(selectedMessage); return true; + case R.id.cancel_transmission: + cancelTransmission(selectedMessage); + return true; default: return super.onContextItemSelected(item); } @@ -428,6 +436,13 @@ public class ConversationFragment extends Fragment { .createNewConnection(message); } + private void cancelTransmission(Message message) { + Downloadable downloadable = message.getDownloadable(); + if (downloadable!=null) { + downloadable.cancel(); + } + } + protected void privateMessageWith(final Jid counterpart) { this.mEditMessage.setText(""); this.conversation.setNextCounterpart(counterpart); diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java index 9a7e16f97..0db145036 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java @@ -10,7 +10,6 @@ import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import android.content.Intent; -import android.graphics.BitmapFactory; import android.net.Uri; import android.os.SystemClock; import android.util.Log; @@ -76,7 +75,7 @@ public class JingleConnection implements Downloadable { @Override public void onIqPacketReceived(Account account, IqPacket packet) { if (packet.getType() == IqPacket.TYPE_ERROR) { - cancel(); + fail(); } } }; @@ -115,7 +114,7 @@ public class JingleConnection implements Downloadable { @Override public void onFileTransferAborted() { JingleConnection.this.sendCancel(); - JingleConnection.this.cancel(); + JingleConnection.this.fail(); } }; @@ -162,14 +161,14 @@ public class JingleConnection implements Downloadable { Reason reason = packet.getReason(); if (reason != null) { if (reason.hasChild("cancel")) { - this.cancel(); + this.fail(); } else if (reason.hasChild("success")) { this.receiveSuccess(); } else { - this.cancel(); + this.fail(); } } else { - this.cancel(); + this.fail(); } } else if (packet.isAction("session-accept")) { returnResult = receiveAccept(packet); @@ -343,7 +342,7 @@ public class JingleConnection implements Downloadable { byte[] key = conversation.getSymmetricKey(); if (key == null) { this.sendCancel(); - this.cancel(); + this.fail(); return; } else { this.file.setKey(key); @@ -352,11 +351,11 @@ public class JingleConnection implements Downloadable { this.file.setExpectedSize(size); } else { this.sendCancel(); - this.cancel(); + this.fail(); } } else { this.sendCancel(); - this.cancel(); + this.fail(); } } @@ -495,7 +494,7 @@ public class JingleConnection implements Downloadable { } else { Log.d(Config.LOGTAG, "activated connection not found"); this.sendCancel(); - this.cancel(); + this.fail(); } } return true; @@ -542,7 +541,7 @@ public class JingleConnection implements Downloadable { this.transport = connection; if (connection == null) { Log.d(Config.LOGTAG, "could not find suitable candidate"); - this.disconnect(); + this.disconnectSocks5Connections(); if (this.initiator.equals(account.getJid())) { this.sendFallbackToIbb(); } @@ -633,7 +632,7 @@ public class JingleConnection implements Downloadable { reason.addChild("success"); packet.setReason(reason); this.sendJinglePacket(packet); - this.disconnect(); + this.disconnectSocks5Connections(); this.mJingleStatus = JINGLE_STATUS_FINISHED; this.message.setStatus(Message.STATUS_RECEIVED); this.message.setDownloadable(null); @@ -710,13 +709,30 @@ public class JingleConnection implements Downloadable { this.mJingleStatus = JINGLE_STATUS_FINISHED; this.mXmppConnectionService.markMessage(this.message, Message.STATUS_SEND); - this.disconnect(); + this.disconnectSocks5Connections(); this.mJingleConnectionManager.finishConnection(this); } public void cancel() { - this.mJingleStatus = JINGLE_STATUS_CANCELED; - this.disconnect(); + this.disconnectSocks5Connections(); + if (this.transport != null && this.transport instanceof JingleInbandTransport) { + this.transport.disconnect(); + } + this.sendCancel(); + this.mJingleConnectionManager.finishConnection(this); + if (this.responder.equals(account.getJid())) { + this.mStatus = Downloadable.STATUS_FAILED; + this.mXmppConnectionService.updateConversationUi(); + } else { + this.mXmppConnectionService.markMessage(this.message, + Message.STATUS_SEND_FAILED); + this.message.setDownloadable(null); + } + } + + private void fail() { + this.mJingleStatus = JINGLE_STATUS_FAILED; + this.disconnectSocks5Connections(); if (this.message != null) { if (this.responder.equals(account.getJid())) { this.mStatus = Downloadable.STATUS_FAILED; @@ -772,7 +788,7 @@ public class JingleConnection implements Downloadable { }); } - private void disconnect() { + private void disconnectSocks5Connections() { Iterator> it = this.connections .entrySet().iterator(); while (it.hasNext()) { diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java index 791f48600..982fa9647 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java @@ -28,6 +28,8 @@ public class JingleInbandTransport extends JingleTransport { private boolean established = false; + private boolean connected = true; + private DownloadableFile file; private JingleConnection connection; @@ -42,7 +44,7 @@ public class JingleInbandTransport extends JingleTransport { private OnIqPacketReceived onAckReceived = new OnIqPacketReceived() { @Override public void onIqPacketReceived(Account account, IqPacket packet) { - if (packet.getType() == IqPacket.TYPE_RESULT) { + if (connected && packet.getType() == IqPacket.TYPE_RESULT) { sendNextBlock(); } } @@ -64,7 +66,7 @@ public class JingleInbandTransport extends JingleTransport { open.setAttribute("sid", this.sessionId); open.setAttribute("stanza", "iq"); open.setAttribute("block-size", Integer.toString(this.blockSize)); - + this.connected = true; this.account.getXmppConnection().sendIqPacket(iq, new OnIqPacketReceived() { @@ -116,12 +118,19 @@ public class JingleInbandTransport extends JingleTransport { callback.onFileTransferAborted(); return; } - this.sendNextBlock(); + if (this.connected) { + this.sendNextBlock(); + } } catch (NoSuchAlgorithmException e) { callback.onFileTransferAborted(); } } + @Override + public void disconnect() { + this.connected = false; + } + private void sendNextBlock() { byte[] buffer = new byte[this.bufferSize]; try { @@ -183,13 +192,14 @@ public class JingleInbandTransport extends JingleTransport { if (payload.getName().equals("open")) { if (!established) { established = true; + connected = true; this.account.getXmppConnection().sendIqPacket( packet.generateRespone(IqPacket.TYPE_RESULT), null); } else { this.account.getXmppConnection().sendIqPacket( packet.generateRespone(IqPacket.TYPE_ERROR), null); } - } else if (payload.getName().equals("data")) { + } else if (connected && payload.getName().equals("data")) { this.receiveNextBlock(payload.getContent()); this.account.getXmppConnection().sendIqPacket( packet.generateRespone(IqPacket.TYPE_RESULT), null); diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleTransport.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleTransport.java index 1374e61cc..e832d3f58 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleTransport.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleTransport.java @@ -10,4 +10,6 @@ public abstract class JingleTransport { public abstract void send(final DownloadableFile file, final OnFileTransmissionStatusChanged callback); + + public abstract void disconnect(); } diff --git a/src/main/res/menu/message_context.xml b/src/main/res/menu/message_context.xml index 80d4d1960..3be52442e 100644 --- a/src/main/res/menu/message_context.xml +++ b/src/main/res/menu/message_context.xml @@ -16,5 +16,8 @@ + \ No newline at end of file diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 3b030e16c..5a01f8a64 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -318,5 +318,6 @@ sending (%1$d%% completed) Preparing file for transmission File offered for download - %s file; + %s file + Cancel transmission From e0f012dba1e8eba3a2d721d685d67ac7901e5c84 Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Sat, 15 Nov 2014 13:19:04 +0100 Subject: [PATCH 10/13] fixed resending for files as well --- .../siacs/conversations/services/XmppConnectionService.java | 6 +++--- .../siacs/conversations/xmpp/jingle/JingleConnection.java | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 06137c642..0383d6ea5 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -714,7 +714,7 @@ public class XmppConnectionService extends Service { if (message.getType() == Message.TYPE_TEXT) { packet = mMessageGenerator.generateOtrChat(message, true); - } else if (message.getType() == Message.TYPE_IMAGE) { + } else if (message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE) { mJingleConnectionManager.createNewConnection(message); } } @@ -726,7 +726,7 @@ public class XmppConnectionService extends Service { || (message.getEncryption() == Message.ENCRYPTION_PGP)) { packet = mMessageGenerator.generatePgpChat(message, true); } - } else if (message.getType() == Message.TYPE_IMAGE) { + } else if (message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE) { Contact contact = message.getConversation().getContact(); Presences presences = contact.getPresences(); if ((message.getCounterpart() != null) @@ -1457,7 +1457,7 @@ public class XmppConnectionService extends Service { databaseBackend.updateMessage(msg); sendMessagePacket(account, outPacket); } - } else if (msg.getType() == Message.TYPE_IMAGE) { + } else if (msg.getType() == Message.TYPE_IMAGE || msg.getType() == Message.TYPE_FILE) { mJingleConnectionManager.createNewConnection(msg); } } diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java index 0db145036..febd4f576 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java @@ -740,6 +740,7 @@ public class JingleConnection implements Downloadable { } else { this.mXmppConnectionService.markMessage(this.message, Message.STATUS_SEND_FAILED); + this.message.setDownloadable(null); } } this.mJingleConnectionManager.finishConnection(this); From 47d44448f3c2e4527b23fcabc4ee65269094eda1 Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Sat, 15 Nov 2014 14:40:43 +0100 Subject: [PATCH 11/13] fixed description in notifications and conversation overview --- .../entities/DownloadablePlaceholder.java | 39 +++++++++++++ .../services/NotificationService.java | 12 +++- .../services/XmppConnectionService.java | 56 +++++-------------- .../ui/ConversationFragment.java | 3 +- .../ui/adapter/ConversationAdapter.java | 12 +++- .../ui/adapter/MessageAdapter.java | 6 +- .../xmpp/jingle/JingleConnection.java | 13 ++++- src/main/res/values/strings.xml | 2 + 8 files changed, 93 insertions(+), 50 deletions(-) create mode 100644 src/main/java/eu/siacs/conversations/entities/DownloadablePlaceholder.java diff --git a/src/main/java/eu/siacs/conversations/entities/DownloadablePlaceholder.java b/src/main/java/eu/siacs/conversations/entities/DownloadablePlaceholder.java new file mode 100644 index 000000000..03fceceb7 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/entities/DownloadablePlaceholder.java @@ -0,0 +1,39 @@ +package eu.siacs.conversations.entities; + +public class DownloadablePlaceholder implements Downloadable { + + private int status; + + public DownloadablePlaceholder(int status) { + this.status = status; + } + @Override + public boolean start() { + return false; + } + + @Override + public int getStatus() { + return status; + } + + @Override + public long getFileSize() { + return 0; + } + + @Override + public int getProgress() { + return 0; + } + + @Override + public String getMimeType() { + return ""; + } + + @Override + public void cancel() { + + } +} diff --git a/src/main/java/eu/siacs/conversations/services/NotificationService.java b/src/main/java/eu/siacs/conversations/services/NotificationService.java index 4cb28145c..385aab927 100644 --- a/src/main/java/eu/siacs/conversations/services/NotificationService.java +++ b/src/main/java/eu/siacs/conversations/services/NotificationService.java @@ -28,6 +28,7 @@ import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Downloadable; +import eu.siacs.conversations.entities.DownloadableFile; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.ui.ConversationActivity; @@ -266,14 +267,21 @@ public class NotificationService { if (message.getDownloadable() != null && (message.getDownloadable().getStatus() == Downloadable.STATUS_OFFER || message .getDownloadable().getStatus() == Downloadable.STATUS_OFFER_CHECK_FILESIZE)) { - return mXmppConnectionService.getText( - R.string.image_offered_for_download).toString(); + if (message.getType() == Message.TYPE_FILE) { + return mXmppConnectionService.getString(R.string.file_offered_for_download); + } else { + return mXmppConnectionService.getText( + R.string.image_offered_for_download).toString(); + } } else if (message.getEncryption() == Message.ENCRYPTION_PGP) { return mXmppConnectionService.getText( R.string.encrypted_message_received).toString(); } else if (message.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) { return mXmppConnectionService.getText(R.string.decryption_failed) .toString(); + } else if (message.getType() == Message.TYPE_FILE) { + DownloadableFile file = mXmppConnectionService.getFileBackend().getFile(message); + return mXmppConnectionService.getString(R.string.file,file.getMimeType()); } else if (message.getType() == Message.TYPE_IMAGE) { return mXmppConnectionService.getText(R.string.image_file) .toString(); diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 0383d6ea5..2e4341f92 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -57,6 +57,7 @@ import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Downloadable; import eu.siacs.conversations.entities.DownloadableFile; +import eu.siacs.conversations.entities.DownloadablePlaceholder; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.MucOptions; import eu.siacs.conversations.entities.MucOptions.OnRenameListener; @@ -711,11 +712,16 @@ public class XmppConnectionService extends Service { } else { if (message.getConversation().getOtrSession() .getSessionStatus() == SessionStatus.ENCRYPTED) { - if (message.getType() == Message.TYPE_TEXT) { - packet = mMessageGenerator.generateOtrChat(message, - true); - } else if (message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE) { - mJingleConnectionManager.createNewConnection(message); + try { + message.setCounterpart(Jid.fromSessionID(message.getConversation().getOtrSession().getSessionID())); + if (message.getType() == Message.TYPE_TEXT) { + packet = mMessageGenerator.generateOtrChat(message, + true); + } else if (message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE) { + mJingleConnectionManager.createNewConnection(message); + } + } catch (InvalidJidException e) { + } } } @@ -885,10 +891,10 @@ public class XmppConnectionService extends Service { private void checkDeletedFiles(Conversation conversation) { for (Message message : conversation.getMessages()) { - if (message.getType() == Message.TYPE_IMAGE + if ((message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE) && message.getEncryption() != Message.ENCRYPTION_PGP) { if (!getFileBackend().isFileAvailable(message)) { - message.setDownloadable(new DeletedDownloadable()); + message.setDownloadable(new DownloadablePlaceholder(Downloadable.STATUS_DELETED)); } } } @@ -901,7 +907,7 @@ public class XmppConnectionService extends Service { && message.getEncryption() != Message.ENCRYPTION_PGP && message.getUuid().equals(uuid)) { if (!getFileBackend().isFileAvailable(message)) { - message.setDownloadable(new DeletedDownloadable()); + message.setDownloadable(new DownloadablePlaceholder(Downloadable.STATUS_DELETED)); updateConversationUi(); } return; @@ -2012,38 +2018,4 @@ public class XmppConnectionService extends Service { return XmppConnectionService.this; } } - - private class DeletedDownloadable implements Downloadable { - - @Override - public boolean start() { - return false; - } - - @Override - public int getStatus() { - return Downloadable.STATUS_DELETED; - } - - @Override - public long getFileSize() { - return 0; - } - - @Override - public int getProgress() { - return 0; - } - - @Override - public String getMimeType() { - return ""; - } - - @Override - public void cancel() { - - } - - } } diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index e15a6bbc7..da788b430 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -44,6 +44,7 @@ import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Downloadable; +import eu.siacs.conversations.entities.DownloadablePlaceholder; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.MucOptions; import eu.siacs.conversations.entities.Presences; @@ -367,7 +368,7 @@ public class ConversationFragment extends Fragment { downloadImage.setVisible(false); } if (this.selectedMessage.getDownloadable() == null - || this.selectedMessage.getDownloadable().getStatus() == Downloadable.STATUS_DELETED) { + || this.selectedMessage.getDownloadable() instanceof DownloadablePlaceholder) { cancelTransmission.setVisible(false); } } 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 b1aea2094..b81544e64 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java @@ -104,7 +104,17 @@ public class ConversationAdapter extends ArrayAdapter { } else if (d.getStatus() == Downloadable.STATUS_OFFER_CHECK_FILESIZE) { mLastMessage.setText(R.string.image_offered_for_download); } else if (d.getStatus() == Downloadable.STATUS_DELETED) { - mLastMessage.setText(R.string.image_file_deleted); + if (message.getType() == Message.TYPE_FILE) { + mLastMessage.setText(R.string.file_deleted); + } else { + mLastMessage.setText(R.string.image_file_deleted); + } + } else if (d.getStatus() == Downloadable.STATUS_FAILED) { + if (message.getType() == Message.TYPE_FILE) { + mLastMessage.setText(R.string.file_transmission_failed); + } else { + mLastMessage.setText(R.string.image_transmission_failed); + } } else if (message.getImageParams().width > 0) { mLastMessage.setVisibility(View.GONE); imagePreview.setVisibility(View.VISIBLE); 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 71795e986..c82f5be79 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -505,7 +505,11 @@ public class MessageAdapter extends ArrayAdapter { } else if (d.getStatus() == Downloadable.STATUS_OFFER_CHECK_FILESIZE) { displayDownloadableMessage(viewHolder, item,activity.getString(R.string.check_image_filesize)); } else if (d.getStatus() == Downloadable.STATUS_FAILED) { - displayInfoMessage(viewHolder, activity.getString(R.string.image_transmission_failed)); + if (item.getType() == Message.TYPE_FILE) { + displayInfoMessage(viewHolder, activity.getString(R.string.file_transmission_failed)); + } else { + displayInfoMessage(viewHolder, activity.getString(R.string.image_transmission_failed)); + } } } else if (item.getType() == Message.TYPE_IMAGE && item.getEncryption() != Message.ENCRYPTION_PGP && item.getEncryption() != Message.ENCRYPTION_DECRYPTION_FAILED) { displayImageMessage(viewHolder, item); diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java index febd4f576..d6bcf55bb 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java @@ -18,6 +18,7 @@ import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Downloadable; import eu.siacs.conversations.entities.DownloadableFile; +import eu.siacs.conversations.entities.DownloadablePlaceholder; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.xml.Element; @@ -96,7 +97,6 @@ public class JingleConnection implements Downloadable { mXmppConnectionService.markMessage(message, Message.STATUS_RECEIVED); } else { - message.setDownloadable(null); if (message.getEncryption() == Message.ENCRYPTION_PGP || message.getEncryption() == Message.ENCRYPTION_DECRYPTED) { file.delete(); } @@ -710,6 +710,10 @@ public class JingleConnection implements Downloadable { this.mXmppConnectionService.markMessage(this.message, Message.STATUS_SEND); this.disconnectSocks5Connections(); + if (this.transport != null && this.transport instanceof JingleInbandTransport) { + this.transport.disconnect(); + } + this.message.setDownloadable(null); this.mJingleConnectionManager.finishConnection(this); } @@ -721,7 +725,7 @@ public class JingleConnection implements Downloadable { this.sendCancel(); this.mJingleConnectionManager.finishConnection(this); if (this.responder.equals(account.getJid())) { - this.mStatus = Downloadable.STATUS_FAILED; + this.message.setDownloadable(new DownloadablePlaceholder(Downloadable.STATUS_FAILED)); this.mXmppConnectionService.updateConversationUi(); } else { this.mXmppConnectionService.markMessage(this.message, @@ -733,9 +737,12 @@ public class JingleConnection implements Downloadable { private void fail() { this.mJingleStatus = JINGLE_STATUS_FAILED; this.disconnectSocks5Connections(); + if (this.transport != null && this.transport instanceof JingleInbandTransport) { + this.transport.disconnect(); + } if (this.message != null) { if (this.responder.equals(account.getJid())) { - this.mStatus = Downloadable.STATUS_FAILED; + this.message.setDownloadable(new DownloadablePlaceholder(Downloadable.STATUS_FAILED)); this.mXmppConnectionService.updateConversationUi(); } else { this.mXmppConnectionService.markMessage(this.message, diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 5a01f8a64..bf7d35a7a 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -320,4 +320,6 @@ File offered for download %s file Cancel transmission + file transmission failed + The file has been deleted From ca2d86cf87ca3eaab5631c2ad3f18cec66a7d86b Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Sat, 15 Nov 2014 14:52:51 +0100 Subject: [PATCH 12/13] better cleanup after unsuccesful transfers --- .../xmpp/jingle/JingleConnection.java | 6 ++++++ .../xmpp/jingle/JingleInbandTransport.java | 16 +++++++++++++++- .../xmpp/jingle/JingleSocks5Transport.java | 14 ++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java index d6bcf55bb..e4e00e433 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java @@ -726,6 +726,9 @@ public class JingleConnection implements Downloadable { this.mJingleConnectionManager.finishConnection(this); if (this.responder.equals(account.getJid())) { this.message.setDownloadable(new DownloadablePlaceholder(Downloadable.STATUS_FAILED)); + if (this.file!=null) { + file.delete(); + } this.mXmppConnectionService.updateConversationUi(); } else { this.mXmppConnectionService.markMessage(this.message, @@ -743,6 +746,9 @@ public class JingleConnection implements Downloadable { if (this.message != null) { if (this.responder.equals(account.getJid())) { this.message.setDownloadable(new DownloadablePlaceholder(Downloadable.STATUS_FAILED)); + if (this.file!=null) { + file.delete(); + } this.mXmppConnectionService.updateConversationUi(); } else { this.mXmppConnectionService.markMessage(this.message, diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java index 982fa9647..04b225d0e 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java @@ -34,7 +34,7 @@ public class JingleInbandTransport extends JingleTransport { private JingleConnection connection; private InputStream fileInputStream = null; - private OutputStream fileOutputStream; + private OutputStream fileOutputStream = null; private long remainingSize = 0; private long fileSize = 0; private MessageDigest digest; @@ -129,6 +129,20 @@ public class JingleInbandTransport extends JingleTransport { @Override public void disconnect() { this.connected = false; + if (this.fileOutputStream != null) { + try { + this.fileOutputStream.close(); + } catch (IOException e) { + + } + } + if (this.fileInputStream != null) { + try { + this.fileInputStream.close(); + } catch (IOException e) { + + } + } } private void sendNextBlock() { diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java index 1ed3fa115..c34195804 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java @@ -197,6 +197,20 @@ public class JingleSocks5Transport extends JingleTransport { } public void disconnect() { + if (this.outputStream != null) { + try { + this.outputStream.close(); + } catch (IOException e) { + + } + } + if (this.inputStream != null) { + try { + this.inputStream.close(); + } catch (IOException e) { + + } + } if (this.socket != null) { try { this.socket.close(); From 41f7848f2ca48b31ad7fd865490347fe26f60c2b Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Sat, 15 Nov 2014 15:16:40 +0100 Subject: [PATCH 13/13] handled more error cases --- .../ui/ConversationFragment.java | 9 +++++++ .../ui/adapter/MessageAdapter.java | 25 +++++++++++++++---- src/main/res/values/strings.xml | 1 + 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index da788b430..8af342a70 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -44,6 +44,7 @@ import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Downloadable; +import eu.siacs.conversations.entities.DownloadableFile; import eu.siacs.conversations.entities.DownloadablePlaceholder; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.MucOptions; @@ -421,6 +422,14 @@ public class ConversationFragment extends Fragment { } private void resendMessage(Message message) { + if (message.getType() == Message.TYPE_FILE || message.getType() == Message.TYPE_IMAGE) { + DownloadableFile file = activity.xmppConnectionService.getFileBackend().getFile(message); + if (!file.exists()) { + Toast.makeText(activity,R.string.file_deleted,Toast.LENGTH_SHORT).show(); + message.setDownloadable(new DownloadablePlaceholder(Downloadable.STATUS_DELETED)); + return; + } + } activity.xmppConnectionService.resendFailedMessages(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 c82f5be79..fc80c2349 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -1,6 +1,8 @@ package eu.siacs.conversations.ui.adapter; import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; import android.graphics.Typeface; import android.net.Uri; import android.text.Spannable; @@ -495,7 +497,11 @@ public class MessageAdapter extends ArrayAdapter { } else if (d.getStatus() == Downloadable.STATUS_CHECKING) { displayInfoMessage(viewHolder,activity.getString(R.string.checking_image)); } else if (d.getStatus() == Downloadable.STATUS_DELETED) { - displayInfoMessage(viewHolder,activity.getString(R.string.image_file_deleted)); + if (item.getType() == Message.TYPE_FILE) { + displayInfoMessage(viewHolder, activity.getString(R.string.file_deleted)); + } else { + displayInfoMessage(viewHolder, activity.getString(R.string.image_file_deleted)); + } } else if (d.getStatus() == Downloadable.STATUS_OFFER) { if (item.getType() == Message.TYPE_FILE) { displayDownloadableMessage(viewHolder,item,activity.getString(R.string.download_file,d.getMimeType())); @@ -558,10 +564,19 @@ public class MessageAdapter extends ArrayAdapter { } public void openDonwloadable(DownloadableFile file) { - Log.d(Config.LOGTAG,"file "+file.getAbsolutePath()); - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setDataAndType(Uri.fromFile(file), file.getMimeType()); - getContext().startActivity(intent); + if (!file.exists()) { + Toast.makeText(activity,R.string.file_deleted,Toast.LENGTH_SHORT).show(); + return; + } + Intent openIntent = new Intent(Intent.ACTION_VIEW); + openIntent.setDataAndType(Uri.fromFile(file), file.getMimeType()); + PackageManager manager = activity.getPackageManager(); + List infos = manager.queryIntentActivities(openIntent, 0); + if (infos.size() > 0) { + getContext().startActivity(openIntent); + } else { + Toast.makeText(activity,R.string.no_application_found_to_open_file,Toast.LENGTH_SHORT).show(); + } } public interface OnContactPictureClicked { diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index bf7d35a7a..3d69e0f3b 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -322,4 +322,5 @@ Cancel transmission file transmission failed The file has been deleted + No application found to open file