Merge tag '1.3.0'
|
@ -1,5 +1,13 @@
|
|||
###Changelog
|
||||
|
||||
####Version 1.3.0
|
||||
* swipe conversations to end them
|
||||
* quickly enable / disable account via slider
|
||||
* share multiple images at once
|
||||
* expert option to distrust system CAs
|
||||
* mlink compatibility
|
||||
* bug fixes
|
||||
|
||||
####Version 1.2.0
|
||||
* Send current location. (requires [plugin](https://play.google.com/store/apps/details?id=eu.siacs.conversations.sharelocation))
|
||||
* Invite multiple contacts at once
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
Conversations: the very last word in instant messaging
|
||||
|
||||
[![Google Play](http://developer.android.com/images/brand/en_generic_rgb_wo_45.png)](https://play.google.com/store/apps/details?id=eu.siacs.conversations)
|
||||
[![Google Play](http://developer.android.com/images/brand/en_generic_rgb_wo_60.png)](https://play.google.com/store/apps/details?id=eu.siacs.conversations) [![Amazon App Store](https://images-na.ssl-images-amazon.com/images/G/01/AmazonMobileApps/amazon-apps-store-us-black.png)](http://www.amazon.com/dp/B00WD35AAC/)
|
||||
|
||||
![screenshots](https://raw.githubusercontent.com/siacs/Conversations/master/screenshots.png)
|
||||
|
||||
|
@ -17,7 +17,8 @@ Conversations: the very last word in instant messaging
|
|||
## Features
|
||||
|
||||
* End-to-end encryption with either [OTR](https://otr.cypherpunks.ca/) or [OpenPGP](http://www.openpgp.org/about_openpgp/)
|
||||
* Sending and receiving images
|
||||
* Send and receive images as well as other kind of files
|
||||
* Share your location via an external [plug-in](https://play.google.com/store/apps/details?id=eu.siacs.conversations.sharelocation)
|
||||
* Indication when your contact has read your message
|
||||
* Intuitive UI that follows Android Design guidelines
|
||||
* Pictures / Avatars for your Contacts
|
||||
|
|
|
@ -34,6 +34,7 @@ dependencies {
|
|||
compile 'com.google.zxing:core:3.1.0'
|
||||
compile 'com.google.zxing:android-integration:3.1.0'
|
||||
compile 'de.measite.minidns:minidns:0.1.3'
|
||||
compile 'de.timroes.android:EnhancedListView:0.3.4'
|
||||
}
|
||||
|
||||
android {
|
||||
|
@ -43,8 +44,8 @@ android {
|
|||
defaultConfig {
|
||||
minSdkVersion 14
|
||||
targetSdkVersion 21
|
||||
versionCode 56
|
||||
versionName "1.2.0"
|
||||
versionCode 60
|
||||
versionName "1.3.0"
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
|
|
|
@ -122,6 +122,13 @@
|
|||
|
||||
<data android:mimeType="*/*" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND_MULTIPLE" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
|
||||
<data android:mimeType="image/*" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name="de.duenndns.ssl.MemorizingActivity"
|
||||
|
|
|
@ -28,6 +28,7 @@ public final class Config {
|
|||
|
||||
public static final boolean NO_PROXY_LOOKUP = false; //useful to debug ibb
|
||||
public static final boolean DISABLE_STRING_PREP = false; // setting to true might increase startup performance
|
||||
public static final boolean EXTENDED_SM_LOGGING = false; // log stanza counts
|
||||
|
||||
public static final long MILLISECONDS_IN_DAY = 24 * 60 * 60 * 1000;
|
||||
public static final long MAM_MAX_CATCHUP = MILLISECONDS_IN_DAY / 2;
|
||||
|
|
|
@ -182,7 +182,7 @@ public class OtrEngine extends OtrCryptoEngineImpl implements OtrEngineHost {
|
|||
packet.setBody(body);
|
||||
packet.addChild("private", "urn:xmpp:carbons:2");
|
||||
packet.addChild("no-copy", "urn:xmpp:hints");
|
||||
packet.addChild("no-store", "urn:xmpp:hints");
|
||||
packet.addChild("no-permanent-store", "urn:xmpp:hints");
|
||||
|
||||
try {
|
||||
Jid jid = Jid.fromSessionID(session);
|
||||
|
@ -202,20 +202,7 @@ public class OtrEngine extends OtrCryptoEngineImpl implements OtrEngineHost {
|
|||
|
||||
@Override
|
||||
public void messageFromAnotherInstanceReceived(SessionID session) {
|
||||
try {
|
||||
Jid jid = Jid.fromSessionID(session);
|
||||
Conversation conversation = mXmppConnectionService.find(account, jid);
|
||||
String id = conversation == null ? null : conversation.getLastReceivedOtrMessageId();
|
||||
if (id != null) {
|
||||
MessagePacket packet = mXmppConnectionService.getMessageGenerator().generateOtrError(jid,id);
|
||||
packet.setFrom(account.getJid());
|
||||
mXmppConnectionService.sendMessagePacket(account,packet);
|
||||
Log.d(Config.LOGTAG,packet.toString());
|
||||
Log.d(Config.LOGTAG,account.getJid().toBareJid().toString()+": unreadable OTR message in "+conversation.getName());
|
||||
}
|
||||
} catch (InvalidJidException e) {
|
||||
return;
|
||||
}
|
||||
sendOtrErrorMessage(session, "Message from another OTR-instance received");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -267,9 +254,28 @@ public class OtrEngine extends OtrCryptoEngineImpl implements OtrEngineHost {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void unreadableMessageReceived(SessionID arg0) throws OtrException {
|
||||
public void unreadableMessageReceived(SessionID session) throws OtrException {
|
||||
Log.d(Config.LOGTAG,"unreadable message received");
|
||||
throw new OtrException(new Exception("unreadable message received"));
|
||||
sendOtrErrorMessage(session, "You sent me an unreadable OTR-encrypted message");
|
||||
}
|
||||
|
||||
public void sendOtrErrorMessage(SessionID session, String errorText) {
|
||||
try {
|
||||
Jid jid = Jid.fromSessionID(session);
|
||||
Conversation conversation = mXmppConnectionService.find(account, jid);
|
||||
String id = conversation == null ? null : conversation.getLastReceivedOtrMessageId();
|
||||
if (id != null) {
|
||||
MessagePacket packet = mXmppConnectionService.getMessageGenerator()
|
||||
.generateOtrError(jid, id, errorText);
|
||||
packet.setFrom(account.getJid());
|
||||
mXmppConnectionService.sendMessagePacket(account,packet);
|
||||
Log.d(Config.LOGTAG,packet.toString());
|
||||
Log.d(Config.LOGTAG,account.getJid().toBareJid().toString()
|
||||
+": unreadable OTR message in "+conversation.getName());
|
||||
}
|
||||
} catch (InvalidJidException e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -229,11 +229,17 @@ public class Account extends AbstractEntity {
|
|||
return jid.getResourcepart();
|
||||
}
|
||||
|
||||
public void setResource(final String resource) {
|
||||
try {
|
||||
jid = Jid.fromParts(jid.getLocalpart(), jid.getDomainpart(), resource);
|
||||
} catch (final InvalidJidException ignored) {
|
||||
public boolean setResource(final String resource) {
|
||||
final String oldResource = jid.getResourcepart();
|
||||
if (oldResource == null || !oldResource.equals(resource)) {
|
||||
try {
|
||||
jid = Jid.fromParts(jid.getLocalpart(), jid.getDomainpart(), resource);
|
||||
return true;
|
||||
} catch (final InvalidJidException ignored) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Jid getJid() {
|
||||
|
|
|
@ -430,23 +430,31 @@ public class Message extends AbstractEntity {
|
|||
}
|
||||
|
||||
public boolean bodyContainsDownloadable() {
|
||||
/**
|
||||
* there are a few cases where spaces result in an unwanted behavior, e.g.
|
||||
* "http://example.com/image.jpg text that will not be shown /abc.png"
|
||||
* or more than one image link in one message.
|
||||
*/
|
||||
if (body.contains(" ")) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
URL url = new URL(this.getBody());
|
||||
URL url = new URL(body);
|
||||
if (!url.getProtocol().equalsIgnoreCase("http")
|
||||
&& !url.getProtocol().equalsIgnoreCase("https")) {
|
||||
return false;
|
||||
}
|
||||
if (url.getPath() == null) {
|
||||
|
||||
String sUrlPath = url.getPath();
|
||||
if (sUrlPath == null || sUrlPath.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
String[] pathParts = url.getPath().split("/");
|
||||
String filename;
|
||||
if (pathParts.length > 0) {
|
||||
filename = pathParts[pathParts.length - 1].toLowerCase();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
String[] extensionParts = filename.split("\\.");
|
||||
|
||||
int iSlashIndex = sUrlPath.lastIndexOf('/') + 1;
|
||||
|
||||
String sLastUrlPath = sUrlPath.substring(iSlashIndex).toLowerCase();
|
||||
|
||||
String[] extensionParts = sLastUrlPath.split("\\.");
|
||||
if (extensionParts.length == 2
|
||||
&& Arrays.asList(Downloadable.VALID_IMAGE_EXTENSIONS).contains(
|
||||
extensionParts[extensionParts.length - 1])) {
|
||||
|
|
|
@ -71,6 +71,7 @@ public class MessageGenerator extends AbstractGenerator {
|
|||
MessagePacket packet = preparePacket(message, addDelay);
|
||||
packet.addChild("private", "urn:xmpp:carbons:2");
|
||||
packet.addChild("no-copy", "urn:xmpp:hints");
|
||||
packet.addChild("no-permanent-store", "urn:xmpp:hints");
|
||||
try {
|
||||
packet.setBody(otrSession.transformSending(message.getBody())[0]);
|
||||
return packet;
|
||||
|
@ -172,7 +173,7 @@ public class MessageGenerator extends AbstractGenerator {
|
|||
return receivedPacket;
|
||||
}
|
||||
|
||||
public MessagePacket generateOtrError(Jid to, String id) {
|
||||
public MessagePacket generateOtrError(Jid to, String id, String errorText) {
|
||||
MessagePacket packet = new MessagePacket();
|
||||
packet.setType(MessagePacket.TYPE_ERROR);
|
||||
packet.setAttribute("id",id);
|
||||
|
@ -181,7 +182,7 @@ public class MessageGenerator extends AbstractGenerator {
|
|||
error.setAttribute("code","406");
|
||||
error.setAttribute("type","modify");
|
||||
error.addChild("not-acceptable","urn:ietf:params:xml:ns:xmpp-stanzas");
|
||||
error.addChild("text").setContent("unreadable OTR message received");
|
||||
error.addChild("text").setContent("?OTR Error:" + errorText);
|
||||
return packet;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,4 +54,11 @@ public class PresenceGenerator extends AbstractGenerator {
|
|||
}
|
||||
return packet;
|
||||
}
|
||||
|
||||
public PresencePacket sendOfflinePresence(Account account) {
|
||||
PresencePacket packet = new PresencePacket();
|
||||
packet.setFrom(account.getJid());
|
||||
packet.setAttribute("type","unavailable");
|
||||
return packet;
|
||||
}
|
||||
}
|
|
@ -391,15 +391,17 @@ public class MessageParser extends AbstractParser implements
|
|||
|
||||
private void parseNonMessage(Element packet, Account account) {
|
||||
final Jid from = packet.getAttributeAsJid("from");
|
||||
if (account.getJid().equals(from)) {
|
||||
return;
|
||||
}
|
||||
if (extractChatState(from == null ? null : mXmppConnectionService.find(account,from), packet)) {
|
||||
mXmppConnectionService.updateConversationUi();
|
||||
}
|
||||
Element invite = extractInvite(packet);
|
||||
if (invite != null) {
|
||||
Conversation conversation = mXmppConnectionService.findOrCreateConversation(account, from, true);
|
||||
Invite invite = extractInvite(packet);
|
||||
if (invite != null && invite.jid != null) {
|
||||
Conversation conversation = mXmppConnectionService.findOrCreateConversation(account, invite.jid, true);
|
||||
if (!conversation.getMucOptions().online()) {
|
||||
Element password = invite.findChild("password");
|
||||
conversation.getMucOptions().setPassword(password == null ? null : password.getContent());
|
||||
conversation.getMucOptions().setPassword(invite.password);
|
||||
mXmppConnectionService.databaseBackend.updateConversation(conversation);
|
||||
mXmppConnectionService.joinMuc(conversation);
|
||||
mXmppConnectionService.updateConversationUi();
|
||||
|
@ -439,16 +441,30 @@ public class MessageParser extends AbstractParser implements
|
|||
}
|
||||
}
|
||||
|
||||
private Element extractInvite(Element message) {
|
||||
private class Invite {
|
||||
Jid jid;
|
||||
String password;
|
||||
Invite(Jid jid, String password) {
|
||||
this.jid = jid;
|
||||
this.password = password;
|
||||
}
|
||||
}
|
||||
|
||||
private Invite extractInvite(Element message) {
|
||||
Element x = message.findChild("x","http://jabber.org/protocol/muc#user");
|
||||
if (x == null) {
|
||||
x = message.findChild("x","jabber:x:conference");
|
||||
}
|
||||
if (x != null && x.hasChild("invite")) {
|
||||
return x;
|
||||
if (x != null) {
|
||||
Element invite = x.findChild("invite");
|
||||
if (invite != null) {
|
||||
Element pw = x.findChild("password");
|
||||
return new Invite(message.getAttributeAsJid("from"), pw != null ? pw.getContent(): null);
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
x = message.findChild("x","jabber:x:conference");
|
||||
if (x != null) {
|
||||
return new Invite(x.getAttributeAsJid("jid"),x.getAttribute("password"));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void parseEvent(final Element event, final Jid from, final Account account) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package eu.siacs.conversations.persistance;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
|
@ -42,8 +43,7 @@ public class FileBackend {
|
|||
|
||||
private static int IMAGE_SIZE = 1920;
|
||||
|
||||
private SimpleDateFormat imageDateFormat = new SimpleDateFormat(
|
||||
"yyyyMMdd_HHmmssSSS", Locale.US);
|
||||
private final SimpleDateFormat imageDateFormat = new SimpleDateFormat("yyyyMMdd_HHmmssSSS", Locale.US);
|
||||
|
||||
private XmppConnectionService mXmppConnectionService;
|
||||
|
||||
|
@ -110,9 +110,7 @@ public class FileBackend {
|
|||
scalledW = size;
|
||||
scalledH = (int) (h / ((double) w / size));
|
||||
}
|
||||
Bitmap scalledBitmap = Bitmap.createScaledBitmap(originalBitmap,
|
||||
scalledW, scalledH, true);
|
||||
return scalledBitmap;
|
||||
return Bitmap.createScaledBitmap(originalBitmap, scalledW, scalledH, true);
|
||||
} else {
|
||||
return originalBitmap;
|
||||
}
|
||||
|
@ -148,31 +146,35 @@ public class FileBackend {
|
|||
}
|
||||
|
||||
public DownloadableFile copyFileToPrivateStorage(Message message, Uri uri) throws FileCopyException {
|
||||
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);
|
||||
file.getParentFile().mkdirs();
|
||||
OutputStream os = null;
|
||||
InputStream is = null;
|
||||
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);
|
||||
file.getParentFile().mkdirs();
|
||||
file.createNewFile();
|
||||
OutputStream os = new FileOutputStream(file);
|
||||
InputStream is = mXmppConnectionService.getContentResolver().openInputStream(uri);
|
||||
os = new FileOutputStream(file);
|
||||
is = mXmppConnectionService.getContentResolver().openInputStream(uri);
|
||||
byte[] buffer = new byte[1024];
|
||||
int length;
|
||||
while ((length = is.read(buffer)) > 0) {
|
||||
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) {
|
||||
} catch(FileNotFoundException e) {
|
||||
throw new FileCopyException(R.string.error_file_not_found);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new FileCopyException(R.string.error_io_exception);
|
||||
} finally {
|
||||
close(os);
|
||||
close(is);
|
||||
}
|
||||
Log.d(Config.LOGTAG, "output file name " + mXmppConnectionService.getFileBackend().getFile(message));
|
||||
return file;
|
||||
}
|
||||
|
||||
public DownloadableFile copyImageToPrivateStorage(Message message, Uri image)
|
||||
|
@ -182,49 +184,48 @@ public class FileBackend {
|
|||
|
||||
private DownloadableFile copyImageToPrivateStorage(Message message,
|
||||
Uri image, int sampleSize) throws FileCopyException {
|
||||
DownloadableFile file = getFile(message);
|
||||
file.getParentFile().mkdirs();
|
||||
InputStream is = null;
|
||||
OutputStream os = null;
|
||||
try {
|
||||
InputStream is = mXmppConnectionService.getContentResolver()
|
||||
.openInputStream(image);
|
||||
DownloadableFile file = getFile(message);
|
||||
file.getParentFile().mkdirs();
|
||||
file.createNewFile();
|
||||
is = mXmppConnectionService.getContentResolver().openInputStream(image);
|
||||
os = new FileOutputStream(file);
|
||||
|
||||
Bitmap originalBitmap;
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
int inSampleSize = (int) Math.pow(2, sampleSize);
|
||||
Log.d(Config.LOGTAG, "reading bitmap with sample size "
|
||||
+ inSampleSize);
|
||||
Log.d(Config.LOGTAG, "reading bitmap with sample size " + inSampleSize);
|
||||
options.inSampleSize = inSampleSize;
|
||||
originalBitmap = BitmapFactory.decodeStream(is, null, options);
|
||||
is.close();
|
||||
if (originalBitmap == null) {
|
||||
throw new FileCopyException(R.string.error_not_an_image_file);
|
||||
}
|
||||
Bitmap scalledBitmap = resize(originalBitmap, IMAGE_SIZE);
|
||||
originalBitmap = null;
|
||||
Bitmap scaledBitmap = resize(originalBitmap, IMAGE_SIZE);
|
||||
int rotation = getRotation(image);
|
||||
if (rotation > 0) {
|
||||
scalledBitmap = rotate(scalledBitmap, rotation);
|
||||
scaledBitmap = rotate(scaledBitmap, rotation);
|
||||
}
|
||||
OutputStream os = new FileOutputStream(file);
|
||||
boolean success = scalledBitmap.compress(
|
||||
Bitmap.CompressFormat.WEBP, 75, os);
|
||||
|
||||
boolean success = scaledBitmap.compress(Bitmap.CompressFormat.WEBP, 75, os);
|
||||
if (!success) {
|
||||
throw new FileCopyException(R.string.error_compressing_image);
|
||||
}
|
||||
os.flush();
|
||||
os.close();
|
||||
long size = file.getSize();
|
||||
int width = scalledBitmap.getWidth();
|
||||
int height = scalledBitmap.getHeight();
|
||||
int width = scaledBitmap.getWidth();
|
||||
int height = scaledBitmap.getHeight();
|
||||
message.setBody(Long.toString(size) + ',' + width + ',' + height);
|
||||
return file;
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new FileCopyException(R.string.error_file_not_found);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new FileCopyException(R.string.error_io_exception);
|
||||
} catch (SecurityException e) {
|
||||
throw new FileCopyException(
|
||||
R.string.error_security_exception_during_image_copy);
|
||||
throw new FileCopyException(R.string.error_security_exception_during_image_copy);
|
||||
} catch (OutOfMemoryError e) {
|
||||
++sampleSize;
|
||||
if (sampleSize <= 3) {
|
||||
|
@ -232,23 +233,24 @@ public class FileBackend {
|
|||
} else {
|
||||
throw new FileCopyException(R.string.error_out_of_memory);
|
||||
}
|
||||
} finally {
|
||||
close(os);
|
||||
close(is);
|
||||
}
|
||||
}
|
||||
|
||||
private int getRotation(Uri image) {
|
||||
InputStream is = null;
|
||||
try {
|
||||
InputStream is = mXmppConnectionService.getContentResolver()
|
||||
.openInputStream(image);
|
||||
is = mXmppConnectionService.getContentResolver().openInputStream(image);
|
||||
return ExifHelper.getOrientation(is);
|
||||
} catch (FileNotFoundException e) {
|
||||
return 0;
|
||||
} finally {
|
||||
close(is);
|
||||
}
|
||||
}
|
||||
|
||||
public Bitmap getImageFromMessage(Message message) {
|
||||
return BitmapFactory.decodeFile(getFile(message).getAbsolutePath());
|
||||
}
|
||||
|
||||
public Bitmap getThumbnail(Message message, int size, boolean cacheOnly)
|
||||
throws FileNotFoundException {
|
||||
Bitmap thumbnail = mXmppConnectionService.getBitmapCache().get(
|
||||
|
@ -257,8 +259,7 @@ public class FileBackend {
|
|||
File file = getFile(message);
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inSampleSize = calcSampleSize(file, size);
|
||||
Bitmap fullsize = BitmapFactory.decodeFile(file.getAbsolutePath(),
|
||||
options);
|
||||
Bitmap fullsize = BitmapFactory.decodeFile(file.getAbsolutePath(),options);
|
||||
if (fullsize == null) {
|
||||
throw new FileNotFoundException();
|
||||
}
|
||||
|
@ -271,13 +272,11 @@ public class FileBackend {
|
|||
|
||||
public Uri getTakePhotoUri() {
|
||||
StringBuilder pathBuilder = new StringBuilder();
|
||||
pathBuilder.append(Environment
|
||||
.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM));
|
||||
pathBuilder.append(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM));
|
||||
pathBuilder.append('/');
|
||||
pathBuilder.append("Camera");
|
||||
pathBuilder.append('/');
|
||||
pathBuilder.append("IMG_" + this.imageDateFormat.format(new Date())
|
||||
+ ".jpg");
|
||||
pathBuilder.append("IMG_" + this.imageDateFormat.format(new Date()) + ".jpg");
|
||||
Uri uri = Uri.parse("file://" + pathBuilder.toString());
|
||||
File file = new File(uri.toString());
|
||||
file.getParentFile().mkdirs();
|
||||
|
@ -325,13 +324,13 @@ public class FileBackend {
|
|||
String filename = getAvatarPath(avatar.getFilename());
|
||||
file = new File(filename + ".tmp");
|
||||
file.getParentFile().mkdirs();
|
||||
OutputStream os = null;
|
||||
try {
|
||||
file.createNewFile();
|
||||
FileOutputStream mFileOutputStream = new FileOutputStream(file);
|
||||
os = new FileOutputStream(file);
|
||||
MessageDigest digest = MessageDigest.getInstance("SHA-1");
|
||||
digest.reset();
|
||||
DigestOutputStream mDigestOutputStream = new DigestOutputStream(
|
||||
mFileOutputStream, digest);
|
||||
DigestOutputStream mDigestOutputStream = new DigestOutputStream(os, digest);
|
||||
mDigestOutputStream.write(avatar.getImageAsBytes());
|
||||
mDigestOutputStream.flush();
|
||||
mDigestOutputStream.close();
|
||||
|
@ -349,6 +348,8 @@ public class FileBackend {
|
|||
return false;
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
return false;
|
||||
} finally {
|
||||
close(os);
|
||||
}
|
||||
}
|
||||
avatar.size = file.length();
|
||||
|
@ -356,8 +357,7 @@ public class FileBackend {
|
|||
}
|
||||
|
||||
public String getAvatarPath(String avatar) {
|
||||
return mXmppConnectionService.getFilesDir().getAbsolutePath()
|
||||
+ "/avatars/" + avatar;
|
||||
return mXmppConnectionService.getFilesDir().getAbsolutePath()+ "/avatars/" + avatar;
|
||||
}
|
||||
|
||||
public Uri getAvatarUri(String avatar) {
|
||||
|
@ -368,10 +368,11 @@ public class FileBackend {
|
|||
if (image == null) {
|
||||
return null;
|
||||
}
|
||||
InputStream is = null;
|
||||
try {
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inSampleSize = calcSampleSize(image, size);
|
||||
InputStream is = mXmppConnectionService.getContentResolver().openInputStream(image);
|
||||
is = mXmppConnectionService.getContentResolver().openInputStream(image);
|
||||
Bitmap input = BitmapFactory.decodeStream(is, null, options);
|
||||
if (input == null) {
|
||||
return null;
|
||||
|
@ -384,6 +385,8 @@ public class FileBackend {
|
|||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
return null;
|
||||
} finally {
|
||||
close(is);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -391,12 +394,15 @@ public class FileBackend {
|
|||
if (image == null) {
|
||||
return null;
|
||||
}
|
||||
InputStream is = null;
|
||||
try {
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inSampleSize = calcSampleSize(image,Math.max(newHeight, newWidth));
|
||||
InputStream is = mXmppConnectionService.getContentResolver().openInputStream(image);
|
||||
is = mXmppConnectionService.getContentResolver().openInputStream(image);
|
||||
Bitmap source = BitmapFactory.decodeStream(is, null, options);
|
||||
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
int sourceWidth = source.getWidth();
|
||||
int sourceHeight = source.getHeight();
|
||||
float xScale = (float) newWidth / sourceWidth;
|
||||
|
@ -408,14 +414,15 @@ public class FileBackend {
|
|||
float top = (newHeight - scaledHeight) / 2;
|
||||
|
||||
RectF targetRect = new RectF(left, top, left + scaledWidth, top + scaledHeight);
|
||||
Bitmap dest = Bitmap.createBitmap(newWidth, newHeight, source.getConfig());
|
||||
Bitmap dest = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(dest);
|
||||
canvas.drawBitmap(source, null, targetRect, null);
|
||||
return dest;
|
||||
} catch (FileNotFoundException e) {
|
||||
return null;
|
||||
} finally {
|
||||
close(is);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public Bitmap cropCenterSquare(Bitmap input, int size) {
|
||||
|
@ -430,7 +437,7 @@ public class FileBackend {
|
|||
float top = (size - outHeight) / 2;
|
||||
RectF target = new RectF(left, top, left + outWidth, top + outHeight);
|
||||
|
||||
Bitmap output = Bitmap.createBitmap(size, size, input.getConfig());
|
||||
Bitmap output = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(output);
|
||||
canvas.drawBitmap(input, null, target, null);
|
||||
return output;
|
||||
|
@ -522,4 +529,13 @@ public class FileBackend {
|
|||
public boolean isFileAvailable(Message message) {
|
||||
return getFile(message).exists();
|
||||
}
|
||||
|
||||
public static void close(Closeable stream) {
|
||||
if (stream != null) {
|
||||
try {
|
||||
stream.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -454,7 +454,7 @@ public class NotificationService {
|
|||
// nick (matched in case-insensitive manner), followed by optional
|
||||
// punctuation (for example "bob: i disagree" or "how are you alice?"),
|
||||
// followed by another word boundary.
|
||||
return Pattern.compile("\\b" + nick + "\\p{Punct}?\\b",
|
||||
return Pattern.compile("\\b" + Pattern.quote(nick) + "\\p{Punct}?\\b",
|
||||
Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
|
||||
}
|
||||
|
||||
|
@ -493,7 +493,7 @@ public class NotificationService {
|
|||
final int cancelIcon;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
mBuilder.setCategory(Notification.CATEGORY_SERVICE);
|
||||
mBuilder.setSmallIcon(R.drawable.ic_import_export_white_48dp);
|
||||
mBuilder.setSmallIcon(R.drawable.ic_import_export_white_24dp);
|
||||
cancelIcon = R.drawable.ic_cancel_white_24dp;
|
||||
} else {
|
||||
mBuilder.setSmallIcon(R.drawable.ic_stat_communication_import_export);
|
||||
|
@ -540,7 +540,7 @@ public class NotificationService {
|
|||
mBuilder.setOngoing(true);
|
||||
//mBuilder.setLights(0xffffffff, 2000, 4000);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
mBuilder.setSmallIcon(R.drawable.ic_warning_white_36dp);
|
||||
mBuilder.setSmallIcon(R.drawable.ic_warning_white_24dp);
|
||||
} else {
|
||||
mBuilder.setSmallIcon(R.drawable.ic_stat_alert_warning);
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ import org.openintents.openpgp.util.OpenPgpServiceConnection;
|
|||
import java.math.BigInteger;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
|
@ -174,13 +175,22 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
|||
public void onContactStatusChanged(Contact contact, boolean online) {
|
||||
Conversation conversation = find(getConversations(), contact);
|
||||
if (conversation != null) {
|
||||
if (online && contact.getPresences().size() > 1) {
|
||||
if (online) {
|
||||
conversation.endOtrIfNeeded();
|
||||
if (contact.getPresences().size() == 1) {
|
||||
sendUnsentMessages(conversation);
|
||||
}
|
||||
} else {
|
||||
conversation.resetOtrSession();
|
||||
}
|
||||
if (online && (contact.getPresences().size() == 1)) {
|
||||
sendUnsentMessages(conversation);
|
||||
if (contact.getPresences().size() >= 1) {
|
||||
if (conversation.hasValidOtrSession()) {
|
||||
String otrResource = conversation.getOtrSession().getSessionID().getUserID();
|
||||
if (!(Arrays.asList(contact.getPresences().asStringArray()).contains(otrResource))) {
|
||||
conversation.endOtrIfNeeded();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
conversation.endOtrIfNeeded();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -532,9 +542,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
|||
ExceptionHelper.init(getApplicationContext());
|
||||
PRNGFixes.apply();
|
||||
this.mRandom = new SecureRandom();
|
||||
this.mMemorizingTrustManager = new MemorizingTrustManager(
|
||||
getApplicationContext());
|
||||
|
||||
updateMemorizingTrustmanager();
|
||||
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
|
||||
final int cacheSize = maxMemory / 8;
|
||||
this.mBitmapCache = new LruCache<String, Bitmap>(cacheSize) {
|
||||
|
@ -1129,6 +1137,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
|||
}
|
||||
|
||||
public void archiveConversation(Conversation conversation) {
|
||||
getNotificationService().clear(conversation);
|
||||
conversation.setStatus(Conversation.STATUS_ARCHIVED);
|
||||
conversation.setNextEncryption(-1);
|
||||
synchronized (this.conversations) {
|
||||
|
@ -1538,6 +1547,9 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
|||
for (Jid invite : jids) {
|
||||
invite(conversation, invite);
|
||||
}
|
||||
if (account.countPresences() > 1) {
|
||||
directInvite(conversation, account.getJid().toBareJid());
|
||||
}
|
||||
if (callback != null) {
|
||||
callback.success(conversation);
|
||||
}
|
||||
|
@ -1700,6 +1712,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
|||
}
|
||||
}
|
||||
}
|
||||
sendOfflinePresence(account);
|
||||
}
|
||||
account.getXmppConnection().disconnect(force);
|
||||
}
|
||||
|
@ -2022,6 +2035,11 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
|||
sendMessagePacket(conversation.getAccount(), packet);
|
||||
}
|
||||
|
||||
public void directInvite(Conversation conversation, Jid jid) {
|
||||
MessagePacket packet = mMessageGenerator.directInvite(conversation,jid);
|
||||
sendMessagePacket(conversation.getAccount(),packet);
|
||||
}
|
||||
|
||||
public void resetSendingToWaiting(Account account) {
|
||||
for (Conversation conversation : getConversations()) {
|
||||
if (conversation.getAccount() == account) {
|
||||
|
@ -2185,6 +2203,21 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
|||
return this.mMemorizingTrustManager;
|
||||
}
|
||||
|
||||
public void setMemorizingTrustManager(MemorizingTrustManager trustManager) {
|
||||
this.mMemorizingTrustManager = trustManager;
|
||||
}
|
||||
|
||||
public void updateMemorizingTrustmanager() {
|
||||
final MemorizingTrustManager tm;
|
||||
final boolean dontTrustSystemCAs = getPreferences().getBoolean("dont_trust_system_cas", false);
|
||||
if (dontTrustSystemCAs) {
|
||||
tm = new MemorizingTrustManager(getApplicationContext(), null);
|
||||
} else {
|
||||
tm = new MemorizingTrustManager(getApplicationContext());
|
||||
}
|
||||
setMemorizingTrustManager(tm);
|
||||
}
|
||||
|
||||
public PowerManager getPowerManager() {
|
||||
return this.pm;
|
||||
}
|
||||
|
@ -2260,6 +2293,10 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
|||
sendPresencePacket(account, mPresenceGenerator.sendPresence(account));
|
||||
}
|
||||
|
||||
public void sendOfflinePresence(final Account account) {
|
||||
sendPresencePacket(account, mPresenceGenerator.sendOfflinePresence(account));
|
||||
}
|
||||
|
||||
public MessageGenerator getMessageGenerator() {
|
||||
return this.mMessageGenerator;
|
||||
}
|
||||
|
|
|
@ -237,6 +237,9 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
|
|||
MenuItem menuItemDeleteBookmark = menu.findItem(R.id.action_delete_bookmark);
|
||||
MenuItem menuItemAdvancedMode = menu.findItem(R.id.action_advanced_mode);
|
||||
menuItemAdvancedMode.setChecked(mAdvancedMode);
|
||||
if (mConversation == null) {
|
||||
return true;
|
||||
}
|
||||
Account account = mConversation.getAccount();
|
||||
if (account.hasBookmarkFor(mConversation.getJid().toBareJid())) {
|
||||
menuItemSaveBookmark.setVisible(false);
|
||||
|
|
|
@ -256,16 +256,19 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
|
|||
MenuItem unblock = menu.findItem(R.id.action_unblock);
|
||||
MenuItem edit = menu.findItem(R.id.action_edit_contact);
|
||||
MenuItem delete = menu.findItem(R.id.action_delete_contact);
|
||||
if (contact == null) {
|
||||
return true;
|
||||
}
|
||||
final XmppConnection connection = contact.getAccount().getXmppConnection();
|
||||
if (connection != null && connection.getFeatures().blocking()) {
|
||||
if (this.contact.isBlocked()) {
|
||||
menu.findItem(R.id.action_block).setVisible(false);
|
||||
block.setVisible(false);
|
||||
} else {
|
||||
menu.findItem(R.id.action_unblock).setVisible(false);
|
||||
unblock.setVisible(false);
|
||||
}
|
||||
} else {
|
||||
menu.findItem(R.id.action_unblock).setVisible(false);
|
||||
menu.findItem(R.id.action_block).setVisible(false);
|
||||
unblock.setVisible(false);
|
||||
block.setVisible(false);
|
||||
}
|
||||
if (!contact.showInRoster()) {
|
||||
edit.setVisible(false);
|
||||
|
@ -275,6 +278,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
|
|||
}
|
||||
|
||||
private void populateView() {
|
||||
invalidateOptionsMenu();
|
||||
setTitle(contact.getDisplayName());
|
||||
if (contact.showInRoster()) {
|
||||
send.setVisibility(View.VISIBLE);
|
||||
|
|
|
@ -5,6 +5,7 @@ import android.app.ActionBar;
|
|||
import android.app.AlertDialog;
|
||||
import android.app.FragmentTransaction;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ClipData;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnClickListener;
|
||||
import android.content.Intent;
|
||||
|
@ -22,14 +23,15 @@ import android.widget.AdapterView;
|
|||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.ListView;
|
||||
import android.widget.PopupMenu;
|
||||
import android.widget.PopupMenu.OnMenuItemClickListener;
|
||||
import android.widget.Toast;
|
||||
|
||||
import net.java.otr4j.session.SessionStatus;
|
||||
import de.timroes.android.listview.EnhancedListView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import eu.siacs.conversations.R;
|
||||
|
@ -69,15 +71,16 @@ public class ConversationActivity extends XmppActivity
|
|||
|
||||
private String mOpenConverstaion = null;
|
||||
private boolean mPanelOpen = true;
|
||||
private Uri mPendingImageUri = null;
|
||||
private Uri mPendingFileUri = null;
|
||||
final private List<Uri> mPendingImageUris = new ArrayList<>();
|
||||
final private List<Uri> mPendingFileUris = new ArrayList<>();
|
||||
private Uri mPendingGeoUri = null;
|
||||
|
||||
private View mContentView;
|
||||
|
||||
private List<Conversation> conversationList = new ArrayList<>();
|
||||
private Conversation swipedConversation = null;
|
||||
private Conversation mSelectedConversation = null;
|
||||
private ListView listView;
|
||||
private EnhancedListView listView;
|
||||
private ConversationFragment mConversationFragment;
|
||||
|
||||
private ArrayAdapter<Conversation> listAdapter;
|
||||
|
@ -140,13 +143,14 @@ public class ConversationActivity extends XmppActivity
|
|||
@Override
|
||||
protected void onCreate(final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (savedInstanceState != null) {mOpenConverstaion = savedInstanceState.getString(
|
||||
STATE_OPEN_CONVERSATION, null);
|
||||
mPanelOpen = savedInstanceState.getBoolean(STATE_PANEL_OPEN, true);
|
||||
String pending = savedInstanceState.getString(STATE_PENDING_URI, null);
|
||||
if (pending != null) {
|
||||
mPendingImageUri = Uri.parse(pending);
|
||||
}
|
||||
if (savedInstanceState != null) {
|
||||
mOpenConverstaion = savedInstanceState.getString(STATE_OPEN_CONVERSATION, null);
|
||||
mPanelOpen = savedInstanceState.getBoolean(STATE_PANEL_OPEN, true);
|
||||
String pending = savedInstanceState.getString(STATE_PENDING_URI, null);
|
||||
if (pending != null) {
|
||||
mPendingImageUris.clear();
|
||||
mPendingImageUris.add(Uri.parse(pending));
|
||||
}
|
||||
}
|
||||
|
||||
setContentView(R.layout.fragment_conversations_overview);
|
||||
|
@ -156,7 +160,7 @@ public class ConversationActivity extends XmppActivity
|
|||
transaction.replace(R.id.selected_conversation, this.mConversationFragment, "conversation");
|
||||
transaction.commit();
|
||||
|
||||
listView = (ListView) findViewById(R.id.list);
|
||||
listView = (EnhancedListView) findViewById(R.id.list);
|
||||
this.listAdapter = new ConversationAdapter(this, conversationList);
|
||||
listView.setAdapter(this.listAdapter);
|
||||
|
||||
|
@ -178,6 +182,73 @@ public class ConversationActivity extends XmppActivity
|
|||
openConversation();
|
||||
}
|
||||
});
|
||||
|
||||
listView.setDismissCallback(new EnhancedListView.OnDismissCallback() {
|
||||
|
||||
@Override
|
||||
public EnhancedListView.Undoable onDismiss(final EnhancedListView enhancedListView, final int position) {
|
||||
|
||||
final int index = listView.getFirstVisiblePosition();
|
||||
View v = listView.getChildAt(0);
|
||||
final int top = (v == null) ? 0 : (v.getTop() - listView.getPaddingTop());
|
||||
|
||||
swipedConversation = listAdapter.getItem(position);
|
||||
listAdapter.remove(swipedConversation);
|
||||
swipedConversation.markRead();
|
||||
xmppConnectionService.getNotificationService().clear(swipedConversation);
|
||||
|
||||
final boolean formerlySelected = (getSelectedConversation() == swipedConversation);
|
||||
if (position == 0 && listAdapter.getCount() == 0) {
|
||||
endConversation(swipedConversation, false, true);
|
||||
return null;
|
||||
} else if (formerlySelected) {
|
||||
setSelectedConversation(listAdapter.getItem(0));
|
||||
ConversationActivity.this.mConversationFragment
|
||||
.reInit(getSelectedConversation());
|
||||
}
|
||||
|
||||
return new EnhancedListView.Undoable() {
|
||||
|
||||
@Override
|
||||
public void undo() {
|
||||
listAdapter.insert(swipedConversation, position);
|
||||
if (formerlySelected) {
|
||||
setSelectedConversation(swipedConversation);
|
||||
ConversationActivity.this.mConversationFragment
|
||||
.reInit(getSelectedConversation());
|
||||
}
|
||||
swipedConversation = null;
|
||||
listView.setSelectionFromTop(index + (listView.getChildCount() < position ? 1 : 0), top);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void discard() {
|
||||
if (!swipedConversation.isRead()
|
||||
&& swipedConversation.getMode() == Conversation.MODE_SINGLE) {
|
||||
swipedConversation = null;
|
||||
return;
|
||||
}
|
||||
endConversation(swipedConversation, false, false);
|
||||
swipedConversation = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
if (swipedConversation.getMode() == Conversation.MODE_MULTI) {
|
||||
return getResources().getString(R.string.title_undo_swipe_out_muc);
|
||||
} else {
|
||||
return getResources().getString(R.string.title_undo_swipe_out_conversation);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
listView.enableSwipeToDismiss();
|
||||
listView.setSwipingLayout(R.id.swipeable_item);
|
||||
listView.setUndoStyle(EnhancedListView.UndoStyle.SINGLE_POPUP);
|
||||
listView.setUndoHideDelay(5000);
|
||||
listView.setRequireTouchBeforeDismiss(false);
|
||||
|
||||
mContentView = findViewById(R.id.content_view_spl);
|
||||
if (mContentView == null) {
|
||||
mContentView = findViewById(R.id.content_view_ll);
|
||||
|
@ -204,6 +275,7 @@ public class ConversationActivity extends XmppActivity
|
|||
|
||||
@Override
|
||||
public void onPanelClosed(View arg0) {
|
||||
listView.discardUndo();
|
||||
openConversation();
|
||||
}
|
||||
|
||||
|
@ -303,7 +375,7 @@ public class ConversationActivity extends XmppActivity
|
|||
if (this.getSelectedConversation().getLatestMessage()
|
||||
.getEncryption() != Message.ENCRYPTION_NONE) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
menuSecure.setIcon(R.drawable.ic_lock_outline_white_48dp);
|
||||
menuSecure.setIcon(R.drawable.ic_lock_white_24dp);
|
||||
} else {
|
||||
menuSecure.setIcon(R.drawable.ic_action_secure);
|
||||
}
|
||||
|
@ -340,13 +412,18 @@ public class ConversationActivity extends XmppActivity
|
|||
switch (attachmentChoice) {
|
||||
case ATTACHMENT_CHOICE_CHOOSE_IMAGE:
|
||||
intent.setAction(Intent.ACTION_GET_CONTENT);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE,true);
|
||||
}
|
||||
intent.setType("image/*");
|
||||
chooser = true;
|
||||
break;
|
||||
case ATTACHMENT_CHOICE_TAKE_PHOTO:
|
||||
mPendingImageUri = xmppConnectionService.getFileBackend().getTakePhotoUri();
|
||||
Uri uri = xmppConnectionService.getFileBackend().getTakePhotoUri();
|
||||
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
|
||||
intent.putExtra(MediaStore.EXTRA_OUTPUT, mPendingImageUri);
|
||||
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
|
||||
mPendingImageUris.clear();
|
||||
mPendingImageUris.add(uri);
|
||||
break;
|
||||
case ATTACHMENT_CHOICE_CHOOSE_FILE:
|
||||
chooser = true;
|
||||
|
@ -485,13 +562,21 @@ public class ConversationActivity extends XmppActivity
|
|||
}
|
||||
|
||||
public void endConversation(Conversation conversation) {
|
||||
showConversationsOverview();
|
||||
endConversation(conversation, true, true);
|
||||
}
|
||||
|
||||
public void endConversation(Conversation conversation, boolean showOverview, boolean reinit) {
|
||||
if (showOverview) {
|
||||
showConversationsOverview();
|
||||
}
|
||||
xmppConnectionService.archiveConversation(conversation);
|
||||
if (conversationList.size() > 0) {
|
||||
setSelectedConversation(conversationList.get(0));
|
||||
this.mConversationFragment.reInit(getSelectedConversation());
|
||||
} else {
|
||||
setSelectedConversation(null);
|
||||
if (reinit) {
|
||||
if (conversationList.size() > 0) {
|
||||
setSelectedConversation(conversationList.get(0));
|
||||
this.mConversationFragment.reInit(getSelectedConversation());
|
||||
} else {
|
||||
setSelectedConversation(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -744,6 +829,7 @@ public class ConversationActivity extends XmppActivity
|
|||
|
||||
@Override
|
||||
public void onPause() {
|
||||
listView.discardUndo();
|
||||
super.onPause();
|
||||
this.mActivityPaused = true;
|
||||
if (this.xmppConnectionServiceBound) {
|
||||
|
@ -779,8 +865,8 @@ public class ConversationActivity extends XmppActivity
|
|||
}
|
||||
savedInstanceState.putBoolean(STATE_PANEL_OPEN,
|
||||
isConversationsOverviewVisable());
|
||||
if (this.mPendingImageUri != null) {
|
||||
savedInstanceState.putString(STATE_PENDING_URI, this.mPendingImageUri.toString());
|
||||
if (this.mPendingImageUris.size() >= 1) {
|
||||
savedInstanceState.putString(STATE_PENDING_URI, this.mPendingImageUris.get(0).toString());
|
||||
}
|
||||
super.onSaveInstanceState(savedInstanceState);
|
||||
}
|
||||
|
@ -819,21 +905,23 @@ public class ConversationActivity extends XmppActivity
|
|||
this.mConversationFragment.reInit(getSelectedConversation());
|
||||
} else {
|
||||
showConversationsOverview();
|
||||
mPendingImageUri = null;
|
||||
mPendingFileUri = null;
|
||||
mPendingImageUris.clear();
|
||||
mPendingFileUris.clear();
|
||||
mPendingGeoUri = null;
|
||||
setSelectedConversation(conversationList.get(0));
|
||||
this.mConversationFragment.reInit(getSelectedConversation());
|
||||
}
|
||||
|
||||
if (mPendingImageUri != null) {
|
||||
attachImageToConversation(getSelectedConversation(),mPendingImageUri);
|
||||
mPendingImageUri = null;
|
||||
} else if (mPendingFileUri != null) {
|
||||
attachFileToConversation(getSelectedConversation(),mPendingFileUri);
|
||||
mPendingFileUri = null;
|
||||
} else if (mPendingGeoUri != null) {
|
||||
attachLocationToConversation(getSelectedConversation(),mPendingGeoUri);
|
||||
for(Iterator<Uri> i = mPendingImageUris.iterator(); i.hasNext(); i.remove()) {
|
||||
attachImageToConversation(getSelectedConversation(),i.next());
|
||||
}
|
||||
|
||||
for(Iterator<Uri> i = mPendingFileUris.iterator(); i.hasNext(); i.remove()) {
|
||||
attachFileToConversation(getSelectedConversation(),i.next());
|
||||
}
|
||||
|
||||
if (mPendingGeoUri != null) {
|
||||
attachLocationToConversation(getSelectedConversation(), mPendingGeoUri);
|
||||
mPendingGeoUri = null;
|
||||
}
|
||||
ExceptionHelper.checkForCrash(this, this.xmppConnectionService);
|
||||
|
@ -841,10 +929,10 @@ public class ConversationActivity extends XmppActivity
|
|||
}
|
||||
|
||||
private void handleViewConversationIntent(final Intent intent) {
|
||||
final String uuid = (String) intent.getExtras().get(CONVERSATION);
|
||||
final String downloadUuid = (String) intent.getExtras().get(MESSAGE);
|
||||
final String text = intent.getExtras().getString(TEXT, "");
|
||||
final String nick = intent.getExtras().getString(NICK, null);
|
||||
final String uuid = intent.getStringExtra(CONVERSATION);
|
||||
final String downloadUuid = intent.getStringExtra(MESSAGE);
|
||||
final String text = intent.getStringExtra(TEXT);
|
||||
final String nick = intent.getStringExtra(NICK);
|
||||
if (selectConversationByUuid(uuid)) {
|
||||
this.mConversationFragment.reInit(getSelectedConversation());
|
||||
if (nick != null) {
|
||||
|
@ -885,6 +973,21 @@ public class ConversationActivity extends XmppActivity
|
|||
xmppConnectionService.getNotificationService().setOpenConversation(null);
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
private static List<Uri> extractUriFromIntent(final Intent intent) {
|
||||
List<Uri> uris = new ArrayList<>();
|
||||
Uri uri = intent.getData();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 && uri == null) {
|
||||
ClipData clipData = intent.getClipData();
|
||||
for(int i = 0; i < clipData.getItemCount(); ++i) {
|
||||
uris.add(clipData.getItemAt(i).getUri());
|
||||
}
|
||||
} else {
|
||||
uris.add(uri);
|
||||
}
|
||||
return uris;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode,
|
||||
final Intent data) {
|
||||
|
@ -894,25 +997,34 @@ public class ConversationActivity extends XmppActivity
|
|||
mConversationFragment.hideSnackbar();
|
||||
mConversationFragment.updateMessages();
|
||||
} else if (requestCode == ATTACHMENT_CHOICE_CHOOSE_IMAGE) {
|
||||
mPendingImageUri = data.getData();
|
||||
mPendingImageUris.clear();
|
||||
mPendingImageUris.addAll(extractUriFromIntent(data));
|
||||
if (xmppConnectionServiceBound) {
|
||||
attachImageToConversation(getSelectedConversation(),mPendingImageUri);
|
||||
mPendingImageUri = null;
|
||||
for(Iterator<Uri> i = mPendingImageUris.iterator(); i.hasNext(); i.remove()) {
|
||||
attachImageToConversation(getSelectedConversation(),i.next());
|
||||
}
|
||||
}
|
||||
} else if (requestCode == ATTACHMENT_CHOICE_CHOOSE_FILE || requestCode == ATTACHMENT_CHOICE_RECORD_VOICE) {
|
||||
mPendingFileUri = data.getData();
|
||||
mPendingFileUris.clear();
|
||||
mPendingFileUris.addAll(extractUriFromIntent(data));
|
||||
if (xmppConnectionServiceBound) {
|
||||
attachFileToConversation(getSelectedConversation(),mPendingFileUri);
|
||||
mPendingFileUri = null;
|
||||
for(Iterator<Uri> i = mPendingImageUris.iterator(); i.hasNext(); i.remove()) {
|
||||
attachFileToConversation(getSelectedConversation(), i.next());
|
||||
}
|
||||
}
|
||||
} else if (requestCode == ATTACHMENT_CHOICE_TAKE_PHOTO && mPendingImageUri != null) {
|
||||
if (xmppConnectionServiceBound) {
|
||||
attachImageToConversation(getSelectedConversation(),mPendingImageUri);
|
||||
mPendingImageUri = null;
|
||||
} else if (requestCode == ATTACHMENT_CHOICE_TAKE_PHOTO) {
|
||||
if (mPendingImageUris.size() == 1) {
|
||||
Uri uri = mPendingImageUris.get(0);
|
||||
if (xmppConnectionServiceBound) {
|
||||
attachImageToConversation(getSelectedConversation(), uri);
|
||||
mPendingImageUris.clear();
|
||||
}
|
||||
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
|
||||
intent.setData(uri);
|
||||
sendBroadcast(intent);
|
||||
} else {
|
||||
mPendingImageUris.clear();
|
||||
}
|
||||
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
|
||||
intent.setData(mPendingImageUri);
|
||||
sendBroadcast(intent);
|
||||
} else if (requestCode == ATTACHMENT_CHOICE_LOCATION) {
|
||||
double latitude = data.getDoubleExtra("latitude",0);
|
||||
double longitude = data.getDoubleExtra("longitude",0);
|
||||
|
@ -923,9 +1035,8 @@ public class ConversationActivity extends XmppActivity
|
|||
}
|
||||
}
|
||||
} else {
|
||||
if (requestCode == ATTACHMENT_CHOICE_TAKE_PHOTO) {
|
||||
mPendingImageUri = null;
|
||||
}
|
||||
mPendingImageUris.clear();
|
||||
mPendingFileUris.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1013,6 +1124,13 @@ public class ConversationActivity extends XmppActivity
|
|||
public void updateConversationList() {
|
||||
xmppConnectionService
|
||||
.populateWithOrderedConversations(conversationList);
|
||||
if (swipedConversation != null) {
|
||||
if (swipedConversation.isRead()) {
|
||||
conversationList.remove(swipedConversation);
|
||||
} else {
|
||||
listView.discardUndo();
|
||||
}
|
||||
}
|
||||
listAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ import android.content.DialogInterface;
|
|||
import android.content.Intent;
|
||||
import android.content.IntentSender;
|
||||
import android.content.IntentSender.SendIntentException;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.text.InputType;
|
||||
import android.view.ContextMenu;
|
||||
|
@ -268,7 +267,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
|
|||
if (conversation.getNextCounterpart() != null) {
|
||||
message.setCounterpart(conversation.getNextCounterpart());
|
||||
message.setType(Message.TYPE_PRIVATE);
|
||||
conversation.setNextCounterpart(null);
|
||||
}
|
||||
}
|
||||
if (conversation.getNextEncryption(activity.forceEncryption()) == Message.ENCRYPTION_OTR) {
|
||||
|
@ -316,8 +314,8 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
|
|||
@Override
|
||||
public View onCreateView(final LayoutInflater inflater,
|
||||
ViewGroup container, Bundle savedInstanceState) {
|
||||
final View view = inflater.inflate(R.layout.fragment_conversation,
|
||||
container, false);
|
||||
final View view = inflater.inflate(R.layout.fragment_conversation,container, false);
|
||||
view.setOnClickListener(null);
|
||||
mEditMessage = (EditMessage) view.findViewById(R.id.textinput);
|
||||
setupIme();
|
||||
mEditMessage.setOnClickListener(new OnClickListener() {
|
||||
|
@ -720,21 +718,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
|
|||
final ConversationActivity activity = (ConversationActivity) getActivity();
|
||||
if (this.conversation != null) {
|
||||
updateSnackBar(this.conversation);
|
||||
final Contact contact = this.conversation.getContact();
|
||||
if (this.conversation.isBlocked()) {
|
||||
|
||||
} else if (!contact.showInRoster()
|
||||
&& contact
|
||||
.getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) {
|
||||
|
||||
} else if (conversation.getMode() == Conversation.MODE_SINGLE) {
|
||||
makeFingerprintWarning();
|
||||
} else if (!conversation.getMucOptions().online()
|
||||
&& conversation.getAccount().getStatus() == Account.State.ONLINE) {
|
||||
|
||||
} else if (this.conversation.isMuted()) {
|
||||
|
||||
}
|
||||
conversation.populateWithMessages(ConversationFragment.this.messageList);
|
||||
for (final Message message : this.messageList) {
|
||||
if (message.getEncryption() == Message.ENCRYPTION_PGP
|
||||
|
@ -781,6 +764,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
|
|||
} catch (final NoSuchElementException ignored) {
|
||||
|
||||
}
|
||||
askForPassphraseIntent = null;
|
||||
activity.xmppConnectionService.updateMessage(message);
|
||||
}
|
||||
|
||||
|
@ -880,10 +864,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
|
|||
}
|
||||
}
|
||||
|
||||
protected void makeFingerprintWarning() {
|
||||
|
||||
}
|
||||
|
||||
protected void showSnackbar(final int message, final int action,
|
||||
final OnClickListener clickListener) {
|
||||
snackbar.setVisibility(View.VISIBLE);
|
||||
|
@ -1020,6 +1000,9 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
|
|||
}
|
||||
|
||||
public void appendText(String text) {
|
||||
if (text == null) {
|
||||
return;
|
||||
}
|
||||
String previous = this.mEditMessage.getText().toString();
|
||||
if (previous.length() != 0 && !previous.endsWith(" ")) {
|
||||
text = " " + text;
|
||||
|
|
|
@ -67,7 +67,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
|
|||
|
||||
@Override
|
||||
public void onClick(final View v) {
|
||||
if (mAccount != null && mAccount.getStatus() == Account.State.DISABLED) {
|
||||
if (mAccount != null && mAccount.getStatus() == Account.State.DISABLED && !accountInfoEdited()) {
|
||||
mAccount.setOption(Account.OPTION_DISABLED, false);
|
||||
xmppConnectionService.updateAccount(mAccount);
|
||||
return;
|
||||
|
@ -237,7 +237,11 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
|
|||
}
|
||||
|
||||
protected void updateSaveButton() {
|
||||
if (mAccount != null && (mAccount.getStatus() == Account.State.CONNECTING || mFetchingAvatar)) {
|
||||
if (accountInfoEdited() && jidToEdit != null) {
|
||||
this.mSaveButton.setText(R.string.save);
|
||||
this.mSaveButton.setEnabled(true);
|
||||
this.mSaveButton.setTextColor(getPrimaryTextColor());
|
||||
} else if (mAccount != null && (mAccount.getStatus() == Account.State.CONNECTING || mFetchingAvatar)) {
|
||||
this.mSaveButton.setEnabled(false);
|
||||
this.mSaveButton.setTextColor(getSecondaryTextColor());
|
||||
this.mSaveButton.setText(R.string.account_status_connecting);
|
||||
|
@ -265,9 +269,9 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
|
|||
}
|
||||
|
||||
protected boolean accountInfoEdited() {
|
||||
return (!this.mAccount.getJid().toBareJid().toString().equals(
|
||||
this.mAccountJid.getText().toString()))
|
||||
|| (!this.mAccount.getPassword().equals(
|
||||
return this.mAccount != null && (!this.mAccount.getJid().toBareJid().toString().equals(
|
||||
this.mAccountJid.getText().toString())
|
||||
|| !this.mAccount.getPassword().equals(
|
||||
this.mPassword.getText().toString()));
|
||||
}
|
||||
|
||||
|
@ -464,7 +468,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
|
|||
} else {
|
||||
this.mServerInfoSm.setText(R.string.server_info_unavailable);
|
||||
}
|
||||
if (features.pubsub()) {
|
||||
if (features.pep()) {
|
||||
this.mServerInfoPep.setText(R.string.server_info_available);
|
||||
} else {
|
||||
this.mServerInfoPep.setText(R.string.server_info_unavailable);
|
||||
|
|
|
@ -168,6 +168,14 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda
|
|||
}
|
||||
}
|
||||
|
||||
public void onClickTglAccountState(Account account, boolean enable) {
|
||||
if (enable) {
|
||||
enableAccount(account);
|
||||
} else {
|
||||
disableAccount(account);
|
||||
}
|
||||
}
|
||||
|
||||
private void publishAvatar(Account account) {
|
||||
Intent intent = new Intent(getApplicationContext(),
|
||||
PublishProfilePictureActivity.class);
|
||||
|
|
|
@ -163,8 +163,7 @@ public class PublishProfilePictureActivity extends XmppActivity {
|
|||
if (jid != null) {
|
||||
this.account = xmppConnectionService.findAccountByJid(jid);
|
||||
if (this.account.getXmppConnection() != null) {
|
||||
this.support = this.account.getXmppConnection()
|
||||
.getFeatures().pubsub();
|
||||
this.support = this.account.getXmppConnection().getFeatures().pep();
|
||||
}
|
||||
if (this.avatarUri == null) {
|
||||
if (this.account.getAvatar() != null
|
||||
|
|
|
@ -1,17 +1,29 @@
|
|||
package eu.siacs.conversations.ui;
|
||||
|
||||
import java.security.KeyStoreException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Locale;
|
||||
|
||||
import eu.siacs.conversations.entities.Account;
|
||||
import de.duenndns.ssl.MemorizingTrustManager;
|
||||
|
||||
import eu.siacs.conversations.R;
|
||||
import eu.siacs.conversations.entities.Account;
|
||||
import eu.siacs.conversations.xmpp.XmppConnection;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Fragment;
|
||||
import android.app.FragmentManager;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.preference.ListPreference;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class SettingsActivity extends XmppActivity implements
|
||||
OnSharedPreferenceChangeListener {
|
||||
|
@ -20,9 +32,12 @@ public class SettingsActivity extends XmppActivity implements
|
|||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
mSettingsFragment = new SettingsFragment();
|
||||
getFragmentManager().beginTransaction()
|
||||
.replace(android.R.id.content, mSettingsFragment).commit();
|
||||
FragmentManager fm = getFragmentManager();
|
||||
mSettingsFragment = (SettingsFragment) fm.findFragmentById(android.R.id.content);
|
||||
if (mSettingsFragment == null || !mSettingsFragment.getClass().equals(SettingsFragment.class)) {
|
||||
mSettingsFragment = new SettingsFragment();
|
||||
fm.beginTransaction().replace(android.R.id.content, mSettingsFragment).commit();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -33,19 +48,78 @@ public class SettingsActivity extends XmppActivity implements
|
|||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
PreferenceManager.getDefaultSharedPreferences(this)
|
||||
.registerOnSharedPreferenceChangeListener(this);
|
||||
ListPreference resources = (ListPreference) mSettingsFragment
|
||||
.findPreference("resource");
|
||||
PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this);
|
||||
ListPreference resources = (ListPreference) mSettingsFragment.findPreference("resource");
|
||||
if (resources != null) {
|
||||
ArrayList<CharSequence> entries = new ArrayList<CharSequence>(
|
||||
Arrays.asList(resources.getEntries()));
|
||||
entries.add(0, Build.MODEL);
|
||||
resources.setEntries(entries.toArray(new CharSequence[entries
|
||||
.size()]));
|
||||
resources.setEntryValues(entries.toArray(new CharSequence[entries
|
||||
.size()]));
|
||||
ArrayList<CharSequence> entries = new ArrayList<>(Arrays.asList(resources.getEntries()));
|
||||
if (!entries.contains(Build.MODEL)) {
|
||||
entries.add(0, Build.MODEL);
|
||||
resources.setEntries(entries.toArray(new CharSequence[entries.size()]));
|
||||
resources.setEntryValues(entries.toArray(new CharSequence[entries.size()]));
|
||||
}
|
||||
}
|
||||
|
||||
final Preference removeCertsPreference = mSettingsFragment.findPreference("remove_trusted_certificates");
|
||||
removeCertsPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
final MemorizingTrustManager mtm = xmppConnectionService.getMemorizingTrustManager();
|
||||
final ArrayList<String> aliases = Collections.list(mtm.getCertificates());
|
||||
if (aliases.size() == 0) {
|
||||
displayToast(getString(R.string.toast_no_trusted_certs));
|
||||
return true;
|
||||
}
|
||||
final ArrayList selectedItems = new ArrayList<Integer>();
|
||||
final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(SettingsActivity.this);
|
||||
dialogBuilder.setTitle(getResources().getString(R.string.dialog_manage_certs_title));
|
||||
dialogBuilder.setMultiChoiceItems(aliases.toArray(new CharSequence[aliases.size()]), null,
|
||||
new DialogInterface.OnMultiChoiceClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int indexSelected,
|
||||
boolean isChecked) {
|
||||
if (isChecked) {
|
||||
selectedItems.add(indexSelected);
|
||||
} else if (selectedItems.contains(indexSelected)) {
|
||||
selectedItems.remove(Integer.valueOf(indexSelected));
|
||||
}
|
||||
if (selectedItems.size() > 0)
|
||||
((AlertDialog) dialog).getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(true);
|
||||
else {
|
||||
((AlertDialog) dialog).getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
dialogBuilder.setPositiveButton(
|
||||
getResources().getString(R.string.dialog_manage_certs_positivebutton), new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
int count = selectedItems.size();
|
||||
if (count > 0) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
try {
|
||||
Integer item = Integer.valueOf(selectedItems.get(i).toString());
|
||||
String alias = aliases.get(item);
|
||||
mtm.deleteCertificate(alias);
|
||||
} catch (KeyStoreException e) {
|
||||
e.printStackTrace();
|
||||
displayToast("Error: " + e.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
if (xmppConnectionServiceBound) {
|
||||
reconnectAccounts();
|
||||
}
|
||||
displayToast(getResources().getQuantityString(R.plurals.toast_delete_certificates, count, count));
|
||||
}
|
||||
}
|
||||
});
|
||||
dialogBuilder.setNegativeButton(getResources().getString(R.string.dialog_manage_certs_negativebutton), null);
|
||||
AlertDialog removeCertsDialog = dialogBuilder.create();
|
||||
removeCertsDialog.show();
|
||||
removeCertsDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -63,9 +137,14 @@ public class SettingsActivity extends XmppActivity implements
|
|||
.toLowerCase(Locale.US);
|
||||
if (xmppConnectionServiceBound) {
|
||||
for (Account account : xmppConnectionService.getAccounts()) {
|
||||
account.setResource(resource);
|
||||
if (!account.isOptionSet(Account.OPTION_DISABLED)) {
|
||||
xmppConnectionService.reconnectAccountInBackground(account);
|
||||
if (account.setResource(resource)) {
|
||||
if (!account.isOptionSet(Account.OPTION_DISABLED)) {
|
||||
XmppConnection connection = account.getXmppConnection();
|
||||
if (connection != null) {
|
||||
connection.resetStreamId();
|
||||
}
|
||||
xmppConnectionService.reconnectAccountInBackground(account);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -79,6 +158,27 @@ public class SettingsActivity extends XmppActivity implements
|
|||
}
|
||||
}
|
||||
}
|
||||
} else if (name.equals("dont_trust_system_cas")) {
|
||||
xmppConnectionService.updateMemorizingTrustmanager();
|
||||
reconnectAccounts();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void displayToast(final String msg) {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Toast.makeText(SettingsActivity.this, msg, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void reconnectAccounts() {
|
||||
for (Account account : xmppConnectionService.getAccounts()) {
|
||||
if (!account.isOptionSet(Account.OPTION_DISABLED)) {
|
||||
xmppConnectionService.reconnectAccountInBackground(account);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ import java.net.URLConnection;
|
|||
import java.net.URLDecoder;
|
||||
import java.nio.charset.UnsupportedCharsetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import eu.siacs.conversations.Config;
|
||||
|
@ -32,7 +33,7 @@ import eu.siacs.conversations.xmpp.jid.Jid;
|
|||
public class ShareWithActivity extends XmppActivity {
|
||||
|
||||
private class Share {
|
||||
public Uri uri;
|
||||
public List<Uri> uris = new ArrayList<>();
|
||||
public boolean image;
|
||||
public String account;
|
||||
public String contact;
|
||||
|
@ -104,7 +105,7 @@ public class ShareWithActivity extends XmppActivity {
|
|||
int position, long arg3) {
|
||||
Conversation conversation = mConversations.get(position);
|
||||
if (conversation.getMode() == Conversation.MODE_SINGLE
|
||||
|| share.uri == null) {
|
||||
|| share.uris.size() == 0) {
|
||||
share(mConversations.get(position));
|
||||
}
|
||||
}
|
||||
|
@ -133,18 +134,32 @@ public class ShareWithActivity extends XmppActivity {
|
|||
|
||||
@Override
|
||||
public void onStart() {
|
||||
final String type = getIntent().getType();
|
||||
final Uri uri = getIntent().getParcelableExtra(Intent.EXTRA_STREAM);
|
||||
if (type != null && uri != null && !type.equalsIgnoreCase("text/plain")) {
|
||||
this.share.uri = uri;
|
||||
this.share.image = type.startsWith("image/") || isImage(uri);
|
||||
} else {
|
||||
this.share.text = getIntent().getStringExtra(Intent.EXTRA_TEXT);
|
||||
super.onStart();
|
||||
Intent intent = getIntent();
|
||||
if (intent == null) {
|
||||
return;
|
||||
}
|
||||
final String type = intent.getType();
|
||||
if (Intent.ACTION_SEND.equals(intent.getAction())) {
|
||||
final Uri uri = getIntent().getParcelableExtra(Intent.EXTRA_STREAM);
|
||||
if (type != null && uri != null && !type.equalsIgnoreCase("text/plain")) {
|
||||
this.share.uris.add(uri);
|
||||
this.share.image = type.startsWith("image/") || isImage(uri);
|
||||
} else {
|
||||
this.share.text = getIntent().getStringExtra(Intent.EXTRA_TEXT);
|
||||
}
|
||||
} else if (Intent.ACTION_SEND_MULTIPLE.equals(intent.getAction())) {
|
||||
this.share.image = type != null && type.startsWith("image/");
|
||||
if (!this.share.image) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.share.uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
|
||||
}
|
||||
if (xmppConnectionServiceBound) {
|
||||
xmppConnectionService.populateWithOrderedConversations(mConversations, this.share.uri == null);
|
||||
xmppConnectionService.populateWithOrderedConversations(mConversations, this.share.image);
|
||||
}
|
||||
super.onStart();
|
||||
|
||||
}
|
||||
|
||||
protected boolean isImage(Uri uri) {
|
||||
|
@ -164,7 +179,7 @@ public class ShareWithActivity extends XmppActivity {
|
|||
return;
|
||||
}
|
||||
xmppConnectionService.populateWithOrderedConversations(mConversations,
|
||||
this.share != null && this.share.uri == null);
|
||||
this.share != null && this.share.uris.size() == 0);
|
||||
}
|
||||
|
||||
private void share() {
|
||||
|
@ -188,7 +203,7 @@ public class ShareWithActivity extends XmppActivity {
|
|||
}
|
||||
|
||||
private void share(final Conversation conversation) {
|
||||
if (share.uri != null) {
|
||||
if (share.uris.size() != 0) {
|
||||
selectPresence(conversation, new OnPresenceSelected() {
|
||||
@Override
|
||||
public void onPresenceSelected() {
|
||||
|
@ -196,22 +211,23 @@ public class ShareWithActivity extends XmppActivity {
|
|||
Toast.makeText(getApplicationContext(),
|
||||
getText(R.string.preparing_image),
|
||||
Toast.LENGTH_LONG).show();
|
||||
ShareWithActivity.this.xmppConnectionService
|
||||
.attachImageToConversation(conversation, share.uri,
|
||||
attachFileCallback);
|
||||
for (Iterator<Uri> i = share.uris.iterator(); i.hasNext(); i.remove()) {
|
||||
ShareWithActivity.this.xmppConnectionService
|
||||
.attachImageToConversation(conversation, i.next(),
|
||||
attachFileCallback);
|
||||
}
|
||||
} else {
|
||||
Toast.makeText(getApplicationContext(),
|
||||
getText(R.string.preparing_file),
|
||||
Toast.LENGTH_LONG).show();
|
||||
ShareWithActivity.this.xmppConnectionService
|
||||
.attachFileToConversation(conversation, share.uri,
|
||||
attachFileCallback);
|
||||
.attachFileToConversation(conversation, share.uris.get(0),
|
||||
attachFileCallback);
|
||||
}
|
||||
switchToConversation(conversation, null, true);
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
||||
} else {
|
||||
switchToConversation(conversation, this.share.text, true);
|
||||
finish();
|
||||
|
|
|
@ -90,6 +90,7 @@ public abstract class XmppActivity extends Activity {
|
|||
|
||||
protected int mPrimaryTextColor;
|
||||
protected int mSecondaryTextColor;
|
||||
protected int mPrimaryBackgroundColor;
|
||||
protected int mSecondaryBackgroundColor;
|
||||
protected int mColorRed;
|
||||
protected int mColorOrange;
|
||||
|
@ -331,6 +332,7 @@ public abstract class XmppActivity extends Activity {
|
|||
mColorOrange = getResources().getColor(R.color.orange);
|
||||
mColorGreen = getResources().getColor(R.color.green);
|
||||
mPrimaryColor = getResources().getColor(R.color.primary);
|
||||
mPrimaryBackgroundColor = getResources().getColor(R.color.primarybackground);
|
||||
mSecondaryBackgroundColor = getResources().getColor(R.color.secondarybackground);
|
||||
this.mTheme = findTheme();
|
||||
setTheme(this.mTheme);
|
||||
|
@ -740,7 +742,11 @@ public abstract class XmppActivity extends Activity {
|
|||
public int getOnlineColor() {
|
||||
return this.mColorGreen;
|
||||
}
|
||||
|
||||
|
||||
public int getPrimaryBackgroundColor() {
|
||||
return this.mPrimaryBackgroundColor;
|
||||
}
|
||||
|
||||
public int getSecondaryBackgroundColor() {
|
||||
return this.mSecondaryBackgroundColor;
|
||||
}
|
||||
|
|
|
@ -5,13 +5,16 @@ import java.util.List;
|
|||
import eu.siacs.conversations.R;
|
||||
import eu.siacs.conversations.entities.Account;
|
||||
import eu.siacs.conversations.ui.XmppActivity;
|
||||
import eu.siacs.conversations.ui.ManageAccountActivity;
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Switch;
|
||||
|
||||
public class AccountAdapter extends ArrayAdapter<Account> {
|
||||
|
||||
|
@ -24,7 +27,7 @@ public class AccountAdapter extends ArrayAdapter<Account> {
|
|||
|
||||
@Override
|
||||
public View getView(int position, View view, ViewGroup parent) {
|
||||
Account account = getItem(position);
|
||||
final Account account = getItem(position);
|
||||
if (view == null) {
|
||||
LayoutInflater inflater = (LayoutInflater) getContext()
|
||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
|
@ -34,21 +37,32 @@ public class AccountAdapter extends ArrayAdapter<Account> {
|
|||
jid.setText(account.getJid().toBareJid().toString());
|
||||
TextView statusView = (TextView) view.findViewById(R.id.account_status);
|
||||
ImageView imageView = (ImageView) view.findViewById(R.id.account_image);
|
||||
imageView.setImageBitmap(activity.avatarService().get(account,
|
||||
activity.getPixel(48)));
|
||||
statusView.setText(getContext().getString(account.getStatus().getReadableId()));
|
||||
switch (account.getStatus()) {
|
||||
case ONLINE:
|
||||
statusView.setTextColor(activity.getOnlineColor());
|
||||
break;
|
||||
case DISABLED:
|
||||
case CONNECTING:
|
||||
statusView.setTextColor(activity.getSecondaryTextColor());
|
||||
break;
|
||||
default:
|
||||
statusView.setTextColor(activity.getWarningTextColor());
|
||||
break;
|
||||
}
|
||||
imageView.setImageBitmap(activity.avatarService().get(account, activity.getPixel(48)));
|
||||
statusView.setText(getContext().getString(account.getStatus().getReadableId()));
|
||||
switch (account.getStatus()) {
|
||||
case ONLINE:
|
||||
statusView.setTextColor(activity.getOnlineColor());
|
||||
break;
|
||||
case DISABLED:
|
||||
case CONNECTING:
|
||||
statusView.setTextColor(activity.getSecondaryTextColor());
|
||||
break;
|
||||
default:
|
||||
statusView.setTextColor(activity.getWarningTextColor());
|
||||
break;
|
||||
}
|
||||
final Switch tglAccountState = (Switch) view.findViewById(R.id.tgl_account_status);
|
||||
final boolean isDisabled = (account.getStatus() == Account.State.DISABLED) ? true : false;
|
||||
tglAccountState.setOnCheckedChangeListener(null);
|
||||
tglAccountState.setChecked(!isDisabled);
|
||||
tglAccountState.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
|
||||
if (b == isDisabled && activity instanceof ManageAccountActivity) {
|
||||
((ManageAccountActivity) activity).onClickTglAccountState(account,b);
|
||||
}
|
||||
}
|
||||
});
|
||||
return view;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,17 +46,10 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> {
|
|||
}
|
||||
Conversation conversation = getItem(position);
|
||||
if (this.activity instanceof ConversationActivity) {
|
||||
ConversationActivity activity = (ConversationActivity) this.activity;
|
||||
if (!activity.isConversationsOverviewHideable()) {
|
||||
if (conversation == activity.getSelectedConversation()) {
|
||||
view.setBackgroundColor(activity
|
||||
.getSecondaryBackgroundColor());
|
||||
} else {
|
||||
view.setBackgroundColor(Color.TRANSPARENT);
|
||||
}
|
||||
} else {
|
||||
view.setBackgroundColor(Color.TRANSPARENT);
|
||||
}
|
||||
View swipeableItem = view.findViewById(R.id.swipeable_item);
|
||||
ConversationActivity a = (ConversationActivity) this.activity;
|
||||
int c = !a.isConversationsOverviewHideable() && conversation == a.getSelectedConversation() ? a.getSecondaryBackgroundColor() : a.getPrimaryBackgroundColor();
|
||||
swipeableItem.setBackgroundColor(c);
|
||||
}
|
||||
TextView convName = (TextView) view.findViewById(R.id.conversation_name);
|
||||
if (conversation.getMode() == Conversation.MODE_SINGLE || activity.useSubjectToIdentifyConference()) {
|
||||
|
|
|
@ -91,6 +91,9 @@ public final class CryptoHelper {
|
|||
}
|
||||
|
||||
public static String prettifyFingerprint(String fingerprint) {
|
||||
if (fingerprint.length() < 40) {
|
||||
return fingerprint;
|
||||
}
|
||||
StringBuilder builder = new StringBuilder(fingerprint);
|
||||
builder.insert(8, " ");
|
||||
builder.insert(17, " ");
|
||||
|
|
|
@ -20,7 +20,7 @@ public class GeoHelper {
|
|||
}
|
||||
|
||||
public static ArrayList<Intent> createGeoIntentsFromMessage(Message message) {
|
||||
final ArrayList<Intent> intents = new ArrayList();
|
||||
final ArrayList<Intent> intents = new ArrayList<>();
|
||||
Matcher matcher = GEO_URI.matcher(message.getBody());
|
||||
if (!matcher.matches()) {
|
||||
return intents;
|
||||
|
|
|
@ -90,7 +90,7 @@ public class XmppConnection implements Runnable {
|
|||
private boolean shouldBind = true;
|
||||
private boolean shouldAuthenticate = true;
|
||||
private Element streamFeatures;
|
||||
private final HashMap<String, List<String>> disco = new HashMap<>();
|
||||
private final HashMap<Jid, Info> disco = new HashMap<>();
|
||||
|
||||
private String streamId = null;
|
||||
private int smVersion = 3;
|
||||
|
@ -334,16 +334,23 @@ public class XmppConnection implements Runnable {
|
|||
} catch (final NumberFormatException ignored) {
|
||||
}
|
||||
sendServiceDiscoveryInfo(account.getServer());
|
||||
sendServiceDiscoveryInfo(account.getJid().toBareJid());
|
||||
sendServiceDiscoveryItems(account.getServer());
|
||||
sendInitialPing();
|
||||
} else if (nextTag.isStart("r")) {
|
||||
tagReader.readElement(nextTag);
|
||||
if (Config.EXTENDED_SM_LOGGING) {
|
||||
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": acknowledging stanza #" + this.stanzasReceived);
|
||||
}
|
||||
final AckPacket ack = new AckPacket(this.stanzasReceived, smVersion);
|
||||
tagWriter.writeStanzaAsync(ack);
|
||||
} else if (nextTag.isStart("a")) {
|
||||
final Element ack = tagReader.readElement(nextTag);
|
||||
lastPacketReceived = SystemClock.elapsedRealtime();
|
||||
final int serverSequence = Integer.parseInt(ack.getAttribute("h"));
|
||||
if (Config.EXTENDED_SM_LOGGING) {
|
||||
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": server acknowledged stanza #" + serverSequence);
|
||||
}
|
||||
final String msgId = this.messageReceipts.get(serverSequence);
|
||||
if (msgId != null) {
|
||||
if (this.acknowledgedListener != null) {
|
||||
|
@ -597,8 +604,10 @@ public class XmppConnection implements Runnable {
|
|||
} else if (this.streamFeatures.hasChild("sm", "urn:xmpp:sm:"
|
||||
+ smVersion)
|
||||
&& streamId != null) {
|
||||
final ResumePacket resume = new ResumePacket(this.streamId,
|
||||
stanzasReceived, smVersion);
|
||||
if (Config.EXTENDED_SM_LOGGING) {
|
||||
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": resuming after stanza #"+stanzasReceived);
|
||||
}
|
||||
final ResumePacket resume = new ResumePacket(this.streamId, stanzasReceived, smVersion);
|
||||
this.tagWriter.writeStanzaAsync(resume);
|
||||
} else if (this.streamFeatures.hasChild("bind") && shouldBind) {
|
||||
sendBindRequest();
|
||||
|
@ -734,6 +743,7 @@ public class XmppConnection implements Runnable {
|
|||
features.blockListRequested = false;
|
||||
disco.clear();
|
||||
sendServiceDiscoveryInfo(account.getServer());
|
||||
sendServiceDiscoveryInfo(account.getJid().toBareJid());
|
||||
sendServiceDiscoveryItems(account.getServer());
|
||||
if (bindListener != null) {
|
||||
bindListener.onBind(account);
|
||||
|
@ -741,34 +751,35 @@ public class XmppConnection implements Runnable {
|
|||
sendInitialPing();
|
||||
}
|
||||
|
||||
private void sendServiceDiscoveryInfo(final Jid server) {
|
||||
if (disco.containsKey(server.toDomainJid().toString())) {
|
||||
if (account.getServer().equals(server.toDomainJid())) {
|
||||
private void sendServiceDiscoveryInfo(final Jid jid) {
|
||||
if (disco.containsKey(jid)) {
|
||||
if (account.getServer().equals(jid)) {
|
||||
enableAdvancedStreamFeatures();
|
||||
}
|
||||
} else {
|
||||
final IqPacket iq = new IqPacket(IqPacket.TYPE.GET);
|
||||
iq.setTo(server.toDomainJid());
|
||||
iq.setTo(jid);
|
||||
iq.query("http://jabber.org/protocol/disco#info");
|
||||
this.sendIqPacket(iq, new OnIqPacketReceived() {
|
||||
|
||||
@Override
|
||||
public void onIqPacketReceived(final Account account, final IqPacket packet) {
|
||||
final List<Element> elements = packet.query().getChildren();
|
||||
final List<String> features = new ArrayList<>();
|
||||
final Info info = new Info();
|
||||
for (final Element element : elements) {
|
||||
if (element.getName().equals("identity")) {
|
||||
if ("irc".equals(element.getAttribute("type"))) {
|
||||
//add fake feature to not confuse irc and real muc
|
||||
features.add("siacs:no:muc");
|
||||
String type = element.getAttribute("type");
|
||||
String category = element.getAttribute("category");
|
||||
if (type != null && category != null) {
|
||||
info.identities.add(new Pair<>(category,type));
|
||||
}
|
||||
} else if (element.getName().equals("feature")) {
|
||||
features.add(element.getAttribute("var"));
|
||||
info.features.add(element.getAttribute("var"));
|
||||
}
|
||||
}
|
||||
disco.put(server.toDomainJid().toString(), features);
|
||||
disco.put(jid, info);
|
||||
|
||||
if (account.getServer().equals(server.toDomainJid())) {
|
||||
if (account.getServer().equals(jid)) {
|
||||
enableAdvancedStreamFeatures();
|
||||
for (final OnAdvancedStreamFeaturesLoaded listener : advancedStreamFeaturesLoadedListeners) {
|
||||
listener.onAdvancedStreamFeaturesAvailable(account);
|
||||
|
@ -784,7 +795,7 @@ public class XmppConnection implements Runnable {
|
|||
sendEnableCarbons();
|
||||
}
|
||||
if (getFeatures().blocking() && !features.blockListRequested) {
|
||||
Log.d(Config.LOGTAG, "Requesting block list");
|
||||
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": Requesting block list");
|
||||
this.sendIqPacket(getIqGenerator().generateGetBlockList(), mXmppConnectionService.getIqParser());
|
||||
}
|
||||
}
|
||||
|
@ -891,7 +902,9 @@ public class XmppConnection implements Runnable {
|
|||
}
|
||||
tagWriter.writeStanzaAsync(packet);
|
||||
if (packet instanceof MessagePacket && packet.getId() != null && this.streamId != null) {
|
||||
Log.d(Config.LOGTAG, "request delivery report for stanza " + stanzasSent);
|
||||
if (Config.EXTENDED_SM_LOGGING) {
|
||||
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": requesting ack for message stanza #" + stanzasSent);
|
||||
}
|
||||
this.messageReceipts.put(stanzasSent, packet.getId());
|
||||
tagWriter.writeStanzaAsync(new RequestPacket(this.smVersion));
|
||||
}
|
||||
|
@ -981,11 +994,15 @@ public class XmppConnection implements Runnable {
|
|||
}
|
||||
}
|
||||
|
||||
public void resetStreamId() {
|
||||
this.streamId = null;
|
||||
}
|
||||
|
||||
public List<String> findDiscoItemsByFeature(final String feature) {
|
||||
final List<String> items = new ArrayList<>();
|
||||
for (final Entry<String, List<String>> cursor : disco.entrySet()) {
|
||||
if (cursor.getValue().contains(feature)) {
|
||||
items.add(cursor.getKey());
|
||||
for (final Entry<Jid, Info> cursor : disco.entrySet()) {
|
||||
if (cursor.getValue().features.contains(feature)) {
|
||||
items.add(cursor.getKey().toString());
|
||||
}
|
||||
}
|
||||
return items;
|
||||
|
@ -1004,10 +1021,12 @@ public class XmppConnection implements Runnable {
|
|||
}
|
||||
|
||||
public String getMucServer() {
|
||||
for (final Entry<String, List<String>> cursor : disco.entrySet()) {
|
||||
final List<String> value = cursor.getValue();
|
||||
if (value.contains("http://jabber.org/protocol/muc") && !value.contains("jabber:iq:gateway") && !value.contains("siacs:no:muc")) {
|
||||
return cursor.getKey();
|
||||
for (final Entry<Jid, Info> cursor : disco.entrySet()) {
|
||||
final Info value = cursor.getValue();
|
||||
if (value.features.contains("http://jabber.org/protocol/muc")
|
||||
&& !value.features.contains("jabber:iq:gateway")
|
||||
&& !value.identities.contains(new Pair<>("conference","irc"))) {
|
||||
return cursor.getKey().toString();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -1062,6 +1081,11 @@ public class XmppConnection implements Runnable {
|
|||
this.lastConnect = 0;
|
||||
}
|
||||
|
||||
private class Info {
|
||||
public final ArrayList<String> features = new ArrayList<>();
|
||||
public final ArrayList<Pair<String,String>> identities = new ArrayList<>();
|
||||
}
|
||||
|
||||
public class Features {
|
||||
XmppConnection connection;
|
||||
private boolean carbonsEnabled = false;
|
||||
|
@ -1073,8 +1097,8 @@ public class XmppConnection implements Runnable {
|
|||
}
|
||||
|
||||
private boolean hasDiscoFeature(final Jid server, final String feature) {
|
||||
return connection.disco.containsKey(server.toDomainJid().toString()) &&
|
||||
connection.disco.get(server.toDomainJid().toString()).contains(feature);
|
||||
return connection.disco.containsKey(server) &&
|
||||
connection.disco.get(server).features.contains(feature);
|
||||
}
|
||||
|
||||
public boolean carbons() {
|
||||
|
@ -1090,24 +1114,35 @@ public class XmppConnection implements Runnable {
|
|||
}
|
||||
|
||||
public boolean sm() {
|
||||
return streamId != null;
|
||||
return streamId != null
|
||||
|| (connection.streamFeatures != null && connection.streamFeatures.hasChild("sm"));
|
||||
}
|
||||
|
||||
public boolean csi() {
|
||||
return connection.streamFeatures != null && connection.streamFeatures.hasChild("csi", "urn:xmpp:csi:0");
|
||||
}
|
||||
|
||||
public boolean pubsub() {
|
||||
return hasDiscoFeature(account.getServer(),
|
||||
"http://jabber.org/protocol/pubsub#publish");
|
||||
public boolean pep() {
|
||||
final Pair<String,String> needle = new Pair<>("pubsub","pep");
|
||||
Info info = disco.get(account.getServer());
|
||||
if (info != null && info.identities.contains(needle)) {
|
||||
return true;
|
||||
} else {
|
||||
info = disco.get(account.getJid().toBareJid());
|
||||
return info != null && info.identities.contains(needle);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean mam() {
|
||||
return hasDiscoFeature(account.getServer(), "urn:xmpp:mam:0");
|
||||
if (hasDiscoFeature(account.getJid().toBareJid(), "urn:xmpp:mam:0")) {
|
||||
return true;
|
||||
} else {
|
||||
return hasDiscoFeature(account.getServer(), "urn:xmpp:mam:0");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean advancedStreamFeaturesLoaded() {
|
||||
return disco.containsKey(account.getServer().toString());
|
||||
return disco.containsKey(account.getServer());
|
||||
}
|
||||
|
||||
public boolean rosterVersioning() {
|
||||
|
|
|
@ -192,7 +192,7 @@ public class JingleConnection implements Downloadable {
|
|||
} else {
|
||||
response = packet.generateResponse(IqPacket.TYPE.ERROR);
|
||||
}
|
||||
account.getXmppConnection().sendIqPacket(response, null);
|
||||
mXmppConnectionService.sendIqPacket(account,response,null);
|
||||
}
|
||||
|
||||
public void init(Message message) {
|
||||
|
@ -317,7 +317,7 @@ public class JingleConnection implements Downloadable {
|
|||
message.setBody(Long.toString(size));
|
||||
conversation.add(message);
|
||||
mXmppConnectionService.updateConversationUi();
|
||||
if (size <= this.mJingleConnectionManager
|
||||
if (size < this.mJingleConnectionManager
|
||||
.getAutoAcceptFileSize()) {
|
||||
Log.d(Config.LOGTAG, "auto accepting file from "
|
||||
+ packet.getFrom());
|
||||
|
@ -459,11 +459,11 @@ public class JingleConnection implements Downloadable {
|
|||
}
|
||||
|
||||
private void sendJinglePacket(JinglePacket packet) {
|
||||
account.getXmppConnection().sendIqPacket(packet, responseListener);
|
||||
mXmppConnectionService.sendIqPacket(account,packet,responseListener);
|
||||
}
|
||||
|
||||
private void sendJinglePacket(JinglePacket packet, OnIqPacketReceived callback) {
|
||||
account.getXmppConnection().sendIqPacket(packet,callback);
|
||||
mXmppConnectionService.sendIqPacket(account,packet,callback);
|
||||
}
|
||||
|
||||
private boolean receiveAccept(JinglePacket packet) {
|
||||
|
@ -556,7 +556,7 @@ public class JingleConnection implements Downloadable {
|
|||
.setAttribute("sid", this.getSessionId());
|
||||
activation.query().addChild("activate")
|
||||
.setContent(this.getCounterPart().toString());
|
||||
this.account.getXmppConnection().sendIqPacket(activation,
|
||||
mXmppConnectionService.sendIqPacket(account,activation,
|
||||
new OnIqPacketReceived() {
|
||||
|
||||
@Override
|
||||
|
|
|
@ -11,6 +11,7 @@ import android.util.Base64;
|
|||
|
||||
import eu.siacs.conversations.entities.Account;
|
||||
import eu.siacs.conversations.entities.DownloadableFile;
|
||||
import eu.siacs.conversations.persistance.FileBackend;
|
||||
import eu.siacs.conversations.utils.CryptoHelper;
|
||||
import eu.siacs.conversations.xml.Element;
|
||||
import eu.siacs.conversations.xmpp.OnIqPacketReceived;
|
||||
|
@ -172,6 +173,7 @@ public class JingleInbandTransport extends JingleTransport {
|
|||
connection.updateProgress((int) ((((double) (this.fileSize - this.remainingSize)) / this.fileSize) * 100));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
FileBackend.close(fileInputStream);
|
||||
this.onFileTransmissionStatusChanged.onFileTransferAborted();
|
||||
}
|
||||
}
|
||||
|
@ -198,6 +200,7 @@ public class JingleInbandTransport extends JingleTransport {
|
|||
connection.updateProgress((int) ((((double) (this.fileSize - this.remainingSize)) / this.fileSize) * 100));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
FileBackend.close(fileOutputStream);
|
||||
this.onFileTransmissionStatusChanged.onFileTransferAborted();
|
||||
}
|
||||
}
|
||||
|
@ -207,6 +210,7 @@ public class JingleInbandTransport extends JingleTransport {
|
|||
if (!established) {
|
||||
established = true;
|
||||
connected = true;
|
||||
this.receiveNextBlock("");
|
||||
this.account.getXmppConnection().sendIqPacket(
|
||||
packet.generateResponse(IqPacket.TYPE.RESULT), null);
|
||||
} else {
|
||||
|
|
|
@ -11,6 +11,7 @@ import java.security.NoSuchAlgorithmException;
|
|||
import java.util.Arrays;
|
||||
|
||||
import eu.siacs.conversations.entities.DownloadableFile;
|
||||
import eu.siacs.conversations.persistance.FileBackend;
|
||||
import eu.siacs.conversations.utils.CryptoHelper;
|
||||
|
||||
public class JingleSocks5Transport extends JingleTransport {
|
||||
|
@ -126,25 +127,19 @@ public class JingleSocks5Transport extends JingleTransport {
|
|||
} catch (NoSuchAlgorithmException e) {
|
||||
callback.onFileTransferAborted();
|
||||
} finally {
|
||||
try {
|
||||
if (fileInputStream != null) {
|
||||
fileInputStream.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
callback.onFileTransferAborted();
|
||||
}
|
||||
FileBackend.close(fileInputStream);
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
|
||||
}
|
||||
|
||||
public void receive(final DownloadableFile file,
|
||||
final OnFileTransmissionStatusChanged callback) {
|
||||
public void receive(final DownloadableFile file, final OnFileTransmissionStatusChanged callback) {
|
||||
new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
OutputStream fileOutputStream = null;
|
||||
try {
|
||||
MessageDigest digest = MessageDigest.getInstance("SHA-1");
|
||||
digest.reset();
|
||||
|
@ -152,7 +147,7 @@ public class JingleSocks5Transport extends JingleTransport {
|
|||
socket.setSoTimeout(30000);
|
||||
file.getParentFile().mkdirs();
|
||||
file.createNewFile();
|
||||
OutputStream fileOutputStream = file.createOutputStream();
|
||||
fileOutputStream = file.createOutputStream();
|
||||
if (fileOutputStream == null) {
|
||||
callback.onFileTransferAborted();
|
||||
return;
|
||||
|
@ -183,6 +178,8 @@ public class JingleSocks5Transport extends JingleTransport {
|
|||
callback.onFileTransferAborted();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
callback.onFileTransferAborted();
|
||||
} finally {
|
||||
FileBackend.close(fileOutputStream);
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
|
|
BIN
src/main/res/drawable-hdpi/ic_add_white_24dp.png
Normal file
After Width: | Height: | Size: 223 B |
BIN
src/main/res/drawable-hdpi/ic_attach_file_white_24dp.png
Normal file
After Width: | Height: | Size: 452 B |
Before Width: | Height: | Size: 363 B |
Before Width: | Height: | Size: 287 B After Width: | Height: | Size: 287 B |
Before Width: | Height: | Size: 348 B |
BIN
src/main/res/drawable-hdpi/ic_delete_grey600_24dp.png
Normal file
After Width: | Height: | Size: 248 B |
BIN
src/main/res/drawable-hdpi/ic_delete_white_24dp.png
Normal file
After Width: | Height: | Size: 246 B |
Before Width: | Height: | Size: 341 B After Width: | Height: | Size: 341 B |
Before Width: | Height: | Size: 419 B |
BIN
src/main/res/drawable-hdpi/ic_edit_white_24dp.png
Normal file
After Width: | Height: | Size: 339 B |
BIN
src/main/res/drawable-hdpi/ic_group_add_white_24dp.png
Normal file
After Width: | Height: | Size: 396 B |
BIN
src/main/res/drawable-hdpi/ic_group_white_24dp.png
Normal file
After Width: | Height: | Size: 417 B |
BIN
src/main/res/drawable-hdpi/ic_import_export_white_24dp.png
Normal file
After Width: | Height: | Size: 300 B |
BIN
src/main/res/drawable-hdpi/ic_lock_open_white_24dp.png
Normal file
After Width: | Height: | Size: 400 B |
Before Width: | Height: | Size: 743 B |
BIN
src/main/res/drawable-hdpi/ic_lock_white_24dp.png
Normal file
After Width: | Height: | Size: 399 B |
BIN
src/main/res/drawable-hdpi/ic_person_add_white_24dp.png
Normal file
After Width: | Height: | Size: 383 B |
Before Width: | Height: | Size: 875 B |
Before Width: | Height: | Size: 217 B |
BIN
src/main/res/drawable-hdpi/ic_search_white_24dp.png
Normal file
After Width: | Height: | Size: 504 B |
Before Width: | Height: | Size: 572 B After Width: | Height: | Size: 572 B |
Before Width: | Height: | Size: 780 B |
Before Width: | Height: | Size: 421 B After Width: | Height: | Size: 421 B |
Before Width: | Height: | Size: 540 B |
BIN
src/main/res/drawable-mdpi/ic_add_white_24dp.png
Normal file
After Width: | Height: | Size: 174 B |
BIN
src/main/res/drawable-mdpi/ic_attach_file_white_24dp.png
Normal file
After Width: | Height: | Size: 332 B |
Before Width: | Height: | Size: 290 B |
BIN
src/main/res/drawable-mdpi/ic_content_copy_grey600_24dp.png
Normal file
After Width: | Height: | Size: 217 B |
BIN
src/main/res/drawable-mdpi/ic_delete_grey600_24dp.png
Normal file
After Width: | Height: | Size: 199 B |
BIN
src/main/res/drawable-mdpi/ic_delete_white_24dp.png
Normal file
After Width: | Height: | Size: 197 B |
BIN
src/main/res/drawable-mdpi/ic_edit_grey600_24dp.png
Normal file
After Width: | Height: | Size: 276 B |
BIN
src/main/res/drawable-mdpi/ic_edit_white_24dp.png
Normal file
After Width: | Height: | Size: 272 B |
BIN
src/main/res/drawable-mdpi/ic_group_add_white_24dp.png
Normal file
After Width: | Height: | Size: 313 B |
BIN
src/main/res/drawable-mdpi/ic_group_white_24dp.png
Normal file
After Width: | Height: | Size: 296 B |
BIN
src/main/res/drawable-mdpi/ic_import_export_white_24dp.png
Normal file
After Width: | Height: | Size: 226 B |
BIN
src/main/res/drawable-mdpi/ic_lock_open_white_24dp.png
Normal file
After Width: | Height: | Size: 290 B |
Before Width: | Height: | Size: 449 B |
BIN
src/main/res/drawable-mdpi/ic_lock_white_24dp.png
Normal file
After Width: | Height: | Size: 296 B |
BIN
src/main/res/drawable-mdpi/ic_person_add_white_24dp.png
Normal file
After Width: | Height: | Size: 289 B |
Before Width: | Height: | Size: 637 B |
Before Width: | Height: | Size: 197 B |
BIN
src/main/res/drawable-mdpi/ic_search_white_24dp.png
Normal file
After Width: | Height: | Size: 346 B |
BIN
src/main/res/drawable-mdpi/ic_settings_grey600_24dp.png
Normal file
After Width: | Height: | Size: 423 B |
BIN
src/main/res/drawable-mdpi/ic_warning_white_24dp.png
Normal file
After Width: | Height: | Size: 328 B |
Before Width: | Height: | Size: 198 B After Width: | Height: | Size: 198 B |
Before Width: | Height: | Size: 576 B After Width: | Height: | Size: 576 B |
Before Width: | Height: | Size: 533 B |
BIN
src/main/res/drawable-xhdpi/ic_content_copy_grey600_24dp.png
Normal file
After Width: | Height: | Size: 320 B |
BIN
src/main/res/drawable-xhdpi/ic_delete_grey600_24dp.png
Normal file
After Width: | Height: | Size: 271 B |
Before Width: | Height: | Size: 270 B After Width: | Height: | Size: 270 B |
BIN
src/main/res/drawable-xhdpi/ic_edit_grey600_24dp.png
Normal file
After Width: | Height: | Size: 379 B |
Before Width: | Height: | Size: 378 B After Width: | Height: | Size: 378 B |
Before Width: | Height: | Size: 484 B After Width: | Height: | Size: 484 B |
Before Width: | Height: | Size: 464 B After Width: | Height: | Size: 464 B |
Before Width: | Height: | Size: 330 B After Width: | Height: | Size: 330 B |
Before Width: | Height: | Size: 513 B After Width: | Height: | Size: 513 B |
Before Width: | Height: | Size: 948 B |
BIN
src/main/res/drawable-xhdpi/ic_lock_white_24dp.png
Normal file
After Width: | Height: | Size: 465 B |
Before Width: | Height: | Size: 423 B After Width: | Height: | Size: 423 B |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 212 B |
Before Width: | Height: | Size: 591 B After Width: | Height: | Size: 591 B |
BIN
src/main/res/drawable-xhdpi/ic_settings_grey600_24dp.png
Normal file
After Width: | Height: | Size: 704 B |
BIN
src/main/res/drawable-xhdpi/ic_warning_white_24dp.png
Normal file
After Width: | Height: | Size: 460 B |
Before Width: | Height: | Size: 222 B After Width: | Height: | Size: 222 B |
Before Width: | Height: | Size: 356 B |
Before Width: | Height: | Size: 870 B After Width: | Height: | Size: 870 B |
Before Width: | Height: | Size: 1.6 KiB |