mirror of
https://github.com/moparisthebest/Conversations
synced 2024-11-28 11:42:15 -05:00
Merge branch 'feature/file_transfer' into development
Conflicts: src/main/res/values/strings.xml
This commit is contained in:
commit
35bf13f5ef
@ -19,6 +19,9 @@ 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 boolean NO_PROXY_LOOKUP = false; //useful to debug ibb
|
||||
|
||||
private Config() {
|
||||
|
||||
|
@ -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 {
|
||||
@ -80,12 +78,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);
|
||||
@ -97,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);
|
||||
@ -199,12 +181,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);
|
||||
|
@ -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;
|
||||
@ -12,10 +12,17 @@ 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();
|
||||
|
||||
public int getStatus();
|
||||
|
||||
public long getFileSize();
|
||||
|
||||
public int getProgress();
|
||||
|
||||
public String getMimeType();
|
||||
|
||||
public void cancel();
|
||||
}
|
||||
|
@ -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,18 @@ public class DownloadableFile extends File {
|
||||
}
|
||||
}
|
||||
|
||||
public String getMimeType() {
|
||||
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 "";
|
||||
}
|
||||
}
|
||||
|
||||
public void setExpectedSize(long size) {
|
||||
this.expectedSize = size;
|
||||
}
|
||||
|
@ -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() {
|
||||
|
||||
}
|
||||
}
|
@ -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 {
|
||||
|
@ -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;
|
||||
@ -37,6 +39,8 @@ public class HttpConnection implements Downloadable {
|
||||
private DownloadableFile file;
|
||||
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;
|
||||
@ -235,10 +239,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);
|
||||
updateProgress((int) ((((double) transmitted) / expected) * 100));
|
||||
}
|
||||
os.flush();
|
||||
os.close();
|
||||
@ -246,19 +254,21 @@ 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,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;
|
||||
@ -272,4 +282,14 @@ public class HttpConnection implements Downloadable {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProgress() {
|
||||
return this.mProgress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMimeType() {
|
||||
return "";
|
||||
}
|
||||
}
|
@ -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) {
|
||||
|
@ -7,6 +7,7 @@ import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URL;
|
||||
import java.security.DigestOutputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
@ -26,6 +27,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;
|
||||
@ -53,22 +56,37 @@ public class FileBackend {
|
||||
}
|
||||
|
||||
public DownloadableFile getFile(Message message, boolean decrypted) {
|
||||
String path = message.getRelativeFilePath();
|
||||
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 || message.getType() == Message.TYPE_TEXT) {
|
||||
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(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/";
|
||||
@ -103,13 +121,60 @@ 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")) {
|
||||
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);
|
||||
if (metaCursor != null) {
|
||||
try {
|
||||
if (metaCursor.moveToFirst()) {
|
||||
path = metaCursor.getString(0);
|
||||
}
|
||||
} finally {
|
||||
metaCursor.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
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 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 +190,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 +202,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 +212,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 +465,34 @@ public class FileBackend {
|
||||
return Uri.parse("file://" + file.getAbsolutePath());
|
||||
}
|
||||
|
||||
public class ImageCopyException extends Exception {
|
||||
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();
|
||||
options.inJustDecodeBounds = true;
|
||||
BitmapFactory.decodeFile(file.getAbsolutePath(), options);
|
||||
int imageHeight = options.outHeight;
|
||||
int imageWidth = options.outWidth;
|
||||
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()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
@ -267,14 +268,21 @@ public class NotificationService {
|
||||
if (message.getDownloadable() != null
|
||||
&& (message.getDownloadable().getStatus() == Downloadable.STATUS_OFFER || message
|
||||
.getDownloadable().getStatus() == Downloadable.STATUS_OFFER_CHECK_FILESIZE)) {
|
||||
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();
|
||||
|
@ -56,6 +56,8 @@ 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.DownloadablePlaceholder;
|
||||
import eu.siacs.conversations.entities.Message;
|
||||
import eu.siacs.conversations.entities.MucOptions;
|
||||
import eu.siacs.conversations.entities.MucOptions.OnRenameListener;
|
||||
@ -211,7 +213,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) {
|
||||
@ -295,7 +297,49 @@ public class XmppConnectionService extends Service {
|
||||
return this.mAvatarService;
|
||||
}
|
||||
|
||||
public Message attachImageToConversation(final Conversation conversation,
|
||||
public void attachFileToConversation(Conversation conversation, final Uri uri, final UiCallback<Message> 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) {
|
||||
message.setRelativeFilePath(path);
|
||||
getFileBackend().updateFileParams(message);
|
||||
if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) {
|
||||
getPgpEngine().encrypt(message, callback);
|
||||
} else {
|
||||
callback.success(message);
|
||||
}
|
||||
} else {
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
getFileBackend().copyFileToPrivateStorage(message, uri);
|
||||
getFileBackend().updateFileParams(message);
|
||||
if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) {
|
||||
getPgpEngine().encrypt(message, callback);
|
||||
} else {
|
||||
callback.success(message);
|
||||
}
|
||||
} catch (FileBackend.FileCopyException e) {
|
||||
callback.error(e.getResId(),message);
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void attachImageToConversation(final Conversation conversation,
|
||||
final Uri uri, final UiCallback<Message> callback) {
|
||||
final Message message;
|
||||
if (conversation.getNextEncryption(forceEncryption()) == Message.ENCRYPTION_PGP) {
|
||||
@ -313,18 +357,17 @@ public class XmppConnectionService extends Service {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
getFileBackend().copyImageToPrivateStorage(message, uri);
|
||||
DownloadableFile file = getFileBackend().copyImageToPrivateStorage(message, uri);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
return message;
|
||||
}
|
||||
|
||||
public Conversation find(Bookmark bookmark) {
|
||||
@ -561,7 +604,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()) {
|
||||
@ -678,12 +721,17 @@ public class XmppConnectionService extends Service {
|
||||
} else {
|
||||
if (message.getConversation().getOtrSession()
|
||||
.getSessionStatus() == SessionStatus.ENCRYPTED) {
|
||||
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) {
|
||||
} else if (message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE) {
|
||||
mJingleConnectionManager.createNewConnection(message);
|
||||
}
|
||||
} catch (InvalidJidException e) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (message.getType() == Message.TYPE_TEXT) {
|
||||
@ -693,7 +741,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)
|
||||
@ -852,10 +900,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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -868,7 +916,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;
|
||||
@ -1424,7 +1472,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);
|
||||
}
|
||||
}
|
||||
@ -1979,23 +2027,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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -52,13 +52,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 +67,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;
|
||||
|
||||
@ -76,7 +78,7 @@ public class ConversationActivity extends XmppActivity implements
|
||||
|
||||
private ArrayAdapter<Conversation> listAdapter;
|
||||
|
||||
private Toast prepareImageToast;
|
||||
private Toast prepareFileToast;
|
||||
|
||||
|
||||
public List<Conversation> getConversationList() {
|
||||
@ -306,13 +308,18 @@ 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.setType("*/*");
|
||||
attachFileIntent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
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,21 +779,40 @@ public class ConversationActivity extends XmppActivity implements
|
||||
}
|
||||
}
|
||||
|
||||
private void attachAudioToConversation(Conversation conversation, Uri uri) {
|
||||
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<Message>() {
|
||||
@Override
|
||||
public void success(Message message) {
|
||||
hidePrepareFileToast();
|
||||
xmppConnectionService.sendMessage(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(int errorCode, Message message) {
|
||||
displayErrorDialog(errorCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void userInputRequried(PendingIntent pi, Message message) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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<Message>() {
|
||||
|
||||
@Override
|
||||
public void userInputRequried(PendingIntent pi,
|
||||
Message object) {
|
||||
hidePrepareImageToast();
|
||||
hidePrepareFileToast();
|
||||
ConversationActivity.this.runIntent(pi,
|
||||
ConversationActivity.REQUEST_SEND_PGP_IMAGE);
|
||||
}
|
||||
@ -791,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();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -42,6 +42,9 @@ 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.DownloadableFile;
|
||||
import eu.siacs.conversations.entities.DownloadablePlaceholder;
|
||||
import eu.siacs.conversations.entities.Message;
|
||||
import eu.siacs.conversations.entities.MucOptions;
|
||||
import eu.siacs.conversations.entities.Presences;
|
||||
@ -354,6 +357,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);
|
||||
@ -370,12 +374,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() instanceof DownloadablePlaceholder) {
|
||||
cancelTransmission.setVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -397,6 +404,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);
|
||||
}
|
||||
@ -423,6 +433,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);
|
||||
}
|
||||
|
||||
@ -439,6 +457,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);
|
||||
|
@ -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<Conversation> {
|
||||
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,35 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
|
||||
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) {
|
||||
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) {
|
||||
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);
|
||||
activity.loadBitmap(message, imagePreview);
|
||||
} else {
|
||||
mLastMessage.setText("");
|
||||
}
|
||||
@ -103,6 +126,11 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
|
||||
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);
|
||||
|
@ -1,16 +1,21 @@
|
||||
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;
|
||||
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 +23,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 +33,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;
|
||||
@ -96,10 +105,11 @@ public class MessageAdapter extends ArrayAdapter<Message> {
|
||||
}
|
||||
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) {
|
||||
@ -111,7 +121,12 @@ public class MessageAdapter extends ArrayAdapter<Message> {
|
||||
info = getContext().getString(R.string.waiting);
|
||||
break;
|
||||
case Message.STATUS_UNSEND:
|
||||
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);
|
||||
@ -181,13 +196,13 @@ public class MessageAdapter extends ArrayAdapter<Message> {
|
||||
}
|
||||
}
|
||||
|
||||
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 +267,11 @@ public class MessageAdapter extends ArrayAdapter<Message> {
|
||||
}
|
||||
|
||||
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 +282,22 @@ public class MessageAdapter extends ArrayAdapter<Message> {
|
||||
viewHolder.download_button.setOnLongClickListener(openContextMenu);
|
||||
}
|
||||
|
||||
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,file.getMimeType()));
|
||||
viewHolder.download_button.setOnClickListener(new OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
openDonwloadable(file);
|
||||
}
|
||||
});
|
||||
viewHolder.download_button.setOnLongClickListener(openContextMenu);
|
||||
}
|
||||
|
||||
private void displayImageMessage(ViewHolder viewHolder,
|
||||
final Message message) {
|
||||
if (viewHolder.download_button != null) {
|
||||
@ -455,42 +486,51 @@ public class MessageAdapter extends ArrayAdapter<Message> {
|
||||
});
|
||||
}
|
||||
|
||||
if (item.getType() == Message.TYPE_IMAGE
|
||||
|| item.getDownloadable() != null) {
|
||||
if (item.getDownloadable() != null && item.getDownloadable().getStatus() != Downloadable.STATUS_UPLOADING) {
|
||||
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);
|
||||
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 {
|
||||
displayDecryptionFailed(viewHolder);
|
||||
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) {
|
||||
if (item.getType() == Message.TYPE_FILE) {
|
||||
displayInfoMessage(viewHolder, activity.getString(R.string.file_deleted));
|
||||
} else {
|
||||
if (item.getEncryption() == Message.ENCRYPTION_PGP) {
|
||||
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) {
|
||||
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);
|
||||
} 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, 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() {
|
||||
@ -507,7 +547,6 @@ public class MessageAdapter extends ArrayAdapter<Message> {
|
||||
} else {
|
||||
displayTextMessage(viewHolder, item);
|
||||
}
|
||||
}
|
||||
|
||||
displayStatus(viewHolder, item);
|
||||
|
||||
@ -524,6 +563,22 @@ public class MessageAdapter extends ArrayAdapter<Message> {
|
||||
}
|
||||
}
|
||||
|
||||
public void openDonwloadable(DownloadableFile file) {
|
||||
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<ResolveInfo> 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 {
|
||||
public void onContactPictureClicked(Message message);
|
||||
}
|
||||
|
@ -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;
|
||||
@ -9,14 +10,15 @@ 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;
|
||||
import eu.siacs.conversations.Config;
|
||||
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;
|
||||
@ -29,9 +31,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;
|
||||
|
||||
@ -46,7 +45,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;
|
||||
@ -62,6 +61,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;
|
||||
|
||||
@ -74,7 +76,7 @@ public class JingleConnection implements Downloadable {
|
||||
@Override
|
||||
public void onIqPacketReceived(Account account, IqPacket packet) {
|
||||
if (packet.getType() == IqPacket.TYPE_ERROR) {
|
||||
cancel();
|
||||
fail();
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -90,16 +92,14 @@ 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);
|
||||
} else {
|
||||
if (message.getEncryption() == Message.ENCRYPTION_PGP || message.getEncryption() == Message.ENCRYPTION_DECRYPTED) {
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
Log.d(Config.LOGTAG,
|
||||
"sucessfully transmitted file:" + file.getAbsolutePath());
|
||||
@ -114,7 +114,7 @@ public class JingleConnection implements Downloadable {
|
||||
@Override
|
||||
public void onFileTransferAborted() {
|
||||
JingleConnection.this.sendCancel();
|
||||
JingleConnection.this.cancel();
|
||||
JingleConnection.this.fail();
|
||||
}
|
||||
};
|
||||
|
||||
@ -161,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);
|
||||
@ -203,6 +203,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();
|
||||
@ -258,7 +260,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,30 +279,42 @@ 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);
|
||||
message.setType(Message.TYPE_IMAGE);
|
||||
} else {
|
||||
this.message
|
||||
.setEncryption(Message.ENCRYPTION_PGP);
|
||||
message.setType(Message.TYPE_FILE);
|
||||
}
|
||||
if (filename[filename.length - 1].equals("otr")) {
|
||||
message.setEncryption(Message.ENCRYPTION_OTR);
|
||||
} else {
|
||||
message.setEncryption(Message.ENCRYPTION_PGP);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
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];
|
||||
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);
|
||||
}
|
||||
}
|
||||
if (supportedFile) {
|
||||
message.setRelativeFilePath(message.getUuid()+"_"+suffix);
|
||||
}
|
||||
long size = Long.parseLong(fileSize.getContent());
|
||||
message.setBody(Long.toString(size));
|
||||
conversation.add(message);
|
||||
@ -329,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);
|
||||
@ -338,15 +351,11 @@ public class JingleConnection implements Downloadable {
|
||||
this.file.setExpectedSize(size);
|
||||
} else {
|
||||
this.sendCancel();
|
||||
this.cancel();
|
||||
this.fail();
|
||||
}
|
||||
} else {
|
||||
this.sendCancel();
|
||||
this.cancel();
|
||||
}
|
||||
} else {
|
||||
this.sendCancel();
|
||||
this.cancel();
|
||||
this.fail();
|
||||
}
|
||||
}
|
||||
|
||||
@ -354,7 +363,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);
|
||||
@ -485,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;
|
||||
@ -532,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();
|
||||
}
|
||||
@ -623,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);
|
||||
@ -654,8 +663,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");
|
||||
@ -677,8 +685,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
|
||||
@ -702,20 +709,51 @@ public class JingleConnection implements Downloadable {
|
||||
this.mJingleStatus = JINGLE_STATUS_FINISHED;
|
||||
this.mXmppConnectionService.markMessage(this.message,
|
||||
Message.STATUS_SEND);
|
||||
this.disconnect();
|
||||
this.disconnectSocks5Connections();
|
||||
if (this.transport != null && this.transport instanceof JingleInbandTransport) {
|
||||
this.transport.disconnect();
|
||||
}
|
||||
this.message.setDownloadable(null);
|
||||
this.mJingleConnectionManager.finishConnection(this);
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
this.mJingleStatus = JINGLE_STATUS_CANCELED;
|
||||
this.disconnect();
|
||||
if (this.message != null) {
|
||||
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.message.setDownloadable(new DownloadablePlaceholder(Downloadable.STATUS_FAILED));
|
||||
if (this.file!=null) {
|
||||
file.delete();
|
||||
}
|
||||
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.transport != null && this.transport instanceof JingleInbandTransport) {
|
||||
this.transport.disconnect();
|
||||
}
|
||||
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,
|
||||
Message.STATUS_SEND_FAILED);
|
||||
this.message.setDownloadable(null);
|
||||
}
|
||||
}
|
||||
this.mJingleConnectionManager.finishConnection(this);
|
||||
@ -764,7 +802,7 @@ public class JingleConnection implements Downloadable {
|
||||
});
|
||||
}
|
||||
|
||||
private void disconnect() {
|
||||
private void disconnectSocks5Connections() {
|
||||
Iterator<Entry<String, JingleSocks5Transport>> it = this.connections
|
||||
.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
@ -856,6 +894,14 @@ public class JingleConnection implements Downloadable {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void updateProgress(int i) {
|
||||
this.mProgress = i;
|
||||
if (SystemClock.elapsedRealtime() - this.mLastGuiRefresh > Config.PROGRESS_UI_UPDATE_INTERVAL) {
|
||||
this.mLastGuiRefresh = SystemClock.elapsedRealtime();
|
||||
mXmppConnectionService.updateConversationUi();
|
||||
}
|
||||
}
|
||||
|
||||
interface OnProxyActivated {
|
||||
public void success();
|
||||
|
||||
@ -900,4 +946,29 @@ public class JingleConnection implements Downloadable {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProgress() {
|
||||
return this.mProgress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String 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";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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;
|
||||
@ -27,11 +28,15 @@ public class JingleInbandTransport extends JingleTransport {
|
||||
|
||||
private boolean established = false;
|
||||
|
||||
private boolean connected = true;
|
||||
|
||||
private DownloadableFile file;
|
||||
private JingleConnection connection;
|
||||
|
||||
private InputStream fileInputStream = null;
|
||||
private OutputStream fileOutputStream;
|
||||
private long remainingSize;
|
||||
private OutputStream fileOutputStream = null;
|
||||
private long remainingSize = 0;
|
||||
private long fileSize = 0;
|
||||
private MessageDigest digest;
|
||||
|
||||
private OnFileTransmissionStatusChanged onFileTransmissionStatusChanged;
|
||||
@ -39,16 +44,16 @@ 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();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
@ -61,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() {
|
||||
|
||||
@ -92,7 +97,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 +109,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();
|
||||
@ -111,12 +118,33 @@ public class JingleInbandTransport extends JingleTransport {
|
||||
callback.onFileTransferAborted();
|
||||
return;
|
||||
}
|
||||
if (this.connected) {
|
||||
this.sendNextBlock();
|
||||
}
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
callback.onFileTransferAborted();
|
||||
}
|
||||
}
|
||||
|
||||
@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() {
|
||||
byte[] buffer = new byte[this.bufferSize];
|
||||
try {
|
||||
@ -126,6 +154,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 +169,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 +185,7 @@ public class JingleInbandTransport extends JingleTransport {
|
||||
}
|
||||
this.remainingSize -= buffer.length;
|
||||
|
||||
|
||||
this.fileOutputStream.write(buffer);
|
||||
|
||||
this.digest.update(buffer);
|
||||
@ -163,6 +194,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();
|
||||
@ -173,13 +206,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);
|
||||
|
@ -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();
|
||||
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) ((((double) 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();
|
||||
@ -189,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();
|
||||
|
@ -10,4 +10,6 @@ public abstract class JingleTransport {
|
||||
|
||||
public abstract void send(final DownloadableFile file,
|
||||
final OnFileTransmissionStatusChanged callback);
|
||||
|
||||
public abstract void disconnect();
|
||||
}
|
||||
|
@ -9,7 +9,6 @@
|
||||
android:title="@string/attach_take_picture"/>
|
||||
<item
|
||||
android:id="@+id/attach_record_voice"
|
||||
android:title="@string/attach_record_voice"
|
||||
android:visible="false"/>
|
||||
android:title="@string/choose_file"/>
|
||||
|
||||
</menu>
|
@ -16,5 +16,8 @@
|
||||
<item
|
||||
android:id="@+id/download_image"
|
||||
android:title="@string/download_image"/>
|
||||
<item
|
||||
android:id="@+id/cancel_transmission"
|
||||
android:title="@string/cancel_transmission" />
|
||||
|
||||
</menu>
|
@ -58,7 +58,7 @@
|
||||
<string name="add_contact">Add contact</string>
|
||||
<string name="send_failed">delivery failed</string>
|
||||
<string name="send_rejected">rejected</string>
|
||||
<string name="receiving_image">Receiving image file. Please wait…</string>
|
||||
<string name="receiving_image">Receiving image file (%1$d%%)</string>
|
||||
<string name="preparing_image">Preparing image for transmission</string>
|
||||
<string name="action_clear_history">Clear history</string>
|
||||
<string name="clear_conversation_history">Clear Conversation History</string>
|
||||
@ -332,4 +332,16 @@
|
||||
<string name="touch_to_disable">Touch to disable foreground service</string>
|
||||
<string name="pref_keep_foreground_service">Keep service in foreground</string>
|
||||
<string name="pref_keep_foreground_service_summary">Prevents the operating system from killing your connection</string>
|
||||
<string name="choose_file">Choose file</string>
|
||||
<string name="receiving_file">Receiving %1$s file (%2$d%% completed)</string>
|
||||
<string name="download_file">Download %s file</string>
|
||||
<string name="open_file">Open %s file</string>
|
||||
<string name="sending_file">sending (%1$d%% completed)</string>
|
||||
<string name="preparing_file">Preparing file for transmission</string>
|
||||
<string name="file_offered_for_download">File offered for download</string>
|
||||
<string name="file">%s file</string>
|
||||
<string name="cancel_transmission">Cancel transmission</string>
|
||||
<string name="file_transmission_failed">file transmission failed</string>
|
||||
<string name="file_deleted">The file has been deleted</string>
|
||||
<string name="no_application_found_to_open_file">No application found to open file</string>
|
||||
</resources>
|
||||
|
Loading…
Reference in New Issue
Block a user