aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian S <christian@pix-art.de>2015-10-01 12:09:16 +0200
committerChristian S <christian@pix-art.de>2015-10-01 12:09:16 +0200
commitdca17b4191e6d68785d7e3534b513c7bafbf85db (patch)
tree00eb51f1035c386e62c3ce87d6a85f5cec38cc6d
parent529958abb7e23cc23be481531ec65d987765bee5 (diff)
parentcb7fcfcc11c2dfcff37fa5035fa356ec810476ec (diff)
Merge branch 'siacs-master' into development
-rw-r--r--CHANGELOG.md4
-rw-r--r--build.gradle2
-rw-r--r--src/main/java/eu/siacs/conversations/entities/MucOptions.java4
-rw-r--r--src/main/java/eu/siacs/conversations/persistance/FileBackend.java21
-rw-r--r--src/main/java/eu/siacs/conversations/services/XmppConnectionService.java19
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ConversationFragment.java43
-rw-r--r--src/main/java/eu/siacs/conversations/ui/EditMessage.java26
-rw-r--r--src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java13
-rw-r--r--src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java32
-rw-r--r--src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java1
10 files changed, 128 insertions, 37 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ae1482c89..d4231cfb9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,7 +2,9 @@
####Version 1.6.12
* added blue tick as read indicator
-* added backup to SD option
+* tab completion for MUC nicks
+* history export to SD card
+* bug fixes
####Version 1.6.11
* optimized app updater and increased app update check period to once a
diff --git a/build.gradle b/build.gradle
index 5ee239e24..884aa027e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -52,7 +52,7 @@ android {
minSdkVersion 14
targetSdkVersion 21
versionCode 99
- versionName "1.6.12 beta"
+ versionName "1.6.12"
project.ext.set(archivesBaseName, archivesBaseName + "-" + versionName);
}
diff --git a/src/main/java/eu/siacs/conversations/entities/MucOptions.java b/src/main/java/eu/siacs/conversations/entities/MucOptions.java
index cf49cf65e..cf078ee52 100644
--- a/src/main/java/eu/siacs/conversations/entities/MucOptions.java
+++ b/src/main/java/eu/siacs/conversations/entities/MucOptions.java
@@ -308,7 +308,9 @@ public class MucOptions {
this.error = ERROR_NO_ERROR;
self = user;
if (mNickChangingInProgress) {
- onRenameListener.onSuccess();
+ if (onRenameListener != null) {
+ onRenameListener.onSuccess();
+ }
mNickChangingInProgress = false;
} else if (this.onJoinListener != null) {
this.onJoinListener.onSuccess();
diff --git a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java
index 7fc7eb64e..66682ee2d 100644
--- a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java
+++ b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java
@@ -260,6 +260,10 @@ public class FileBackend {
}
}
+ private int getRotation(File file) {
+ return getRotation(Uri.parse("file://"+file.getAbsolutePath()));
+ }
+
private int getRotation(Uri image) {
InputStream is = null;
try {
@@ -274,8 +278,7 @@ public class FileBackend {
public Bitmap getThumbnail(Message message, int size, boolean cacheOnly)
throws FileNotFoundException {
- Bitmap thumbnail = mXmppConnectionService.getBitmapCache().get(
- message.getUuid());
+ Bitmap thumbnail = mXmppConnectionService.getBitmapCache().get(message.getUuid());
if ((thumbnail == null) && (!cacheOnly)) {
File file = getFile(message);
BitmapFactory.Options options = new BitmapFactory.Options();
@@ -285,8 +288,12 @@ public class FileBackend {
throw new FileNotFoundException();
}
thumbnail = resize(fullsize, size);
- this.mXmppConnectionService.getBitmapCache().put(message.getUuid(),
- thumbnail);
+ fullsize.recycle();
+ int rotation = getRotation(file);
+ if (rotation > 0) {
+ thumbnail = rotate(thumbnail, rotation);
+ }
+ this.mXmppConnectionService.getBitmapCache().put(message.getUuid(),thumbnail);
}
return thumbnail;
}
@@ -512,8 +519,10 @@ public class FileBackend {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(file.getAbsolutePath(), options);
- int imageHeight = options.outHeight;
- int imageWidth = options.outWidth;
+ int rotation = getRotation(file);
+ boolean rotated = rotation == 90 || rotation == 270;
+ int imageHeight = rotated ? options.outWidth : options.outHeight;
+ int imageWidth = rotated ? options.outHeight : options.outWidth;
if (url == null) {
message.setBody(Long.toString(file.getSize()) + '|' + imageWidth + '|' + imageHeight);
} else {
diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
index ee0ccd4f7..fe5272b00 100644
--- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
+++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
@@ -282,7 +282,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
} else if (account.getStatus() == Account.State.REGISTRATION_SUCCESSFUL) {
databaseBackend.updateAccount(account);
- reconnectAccount(account, true);
+ reconnectAccount(account, true, false);
} else if ((account.getStatus() != Account.State.CONNECTING)
&& (account.getStatus() != Account.State.NO_INTERNET)) {
if (connection != null) {
@@ -442,6 +442,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
final String action = intent == null ? null : intent.getAction();
+ boolean interactive = false;
if (action != null) {
switch (action) {
case ConnectivityManager.CONNECTIVITY_ACTION:
@@ -468,6 +469,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
break;
case ACTION_TRY_AGAIN:
resetAllAttemptCounts(false);
+ interactive = true;
break;
case ACTION_DISABLE_ACCOUNT:
try {
@@ -508,7 +510,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
if (lastSent > lastReceived) {
if (pingTimeoutIn < 0) {
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": ping timeout");
- this.reconnectAccount(account, true);
+ this.reconnectAccount(account, true, interactive);
} else {
int secs = (int) (pingTimeoutIn / 1000);
this.scheduleWakeUpCall(secs,account.getUuid().hashCode());
@@ -521,18 +523,18 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
this.scheduleWakeUpCall((int) (msToNextPing / 1000), account.getUuid().hashCode());
}
} else if (account.getStatus() == Account.State.OFFLINE) {
- reconnectAccount(account,true);
+ reconnectAccount(account,true, interactive);
} else if (account.getStatus() == Account.State.CONNECTING) {
long timeout = Config.CONNECT_TIMEOUT - ((SystemClock.elapsedRealtime() - account.getXmppConnection().getLastConnect()) / 1000);
if (timeout < 0) {
Log.d(Config.LOGTAG, account.getJid() + ": time out during connect reconnecting");
- reconnectAccount(account, true);
+ reconnectAccount(account, true, interactive);
} else {
scheduleWakeUpCall((int) timeout,account.getUuid().hashCode());
}
} else {
if (account.getXmppConnection().getTimeToNextAttempt() <= 0) {
- reconnectAccount(account, true);
+ reconnectAccount(account, true, interactive);
}
}
@@ -1208,7 +1210,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
public void updateAccount(final Account account) {
this.statusListener.onStatusChanged(account);
databaseBackend.updateAccount(account);
- reconnectAccount(account, false);
+ reconnectAccount(account, false, true);
updateAccountUi();
getNotificationService().updateErrorNotification();
}
@@ -2145,7 +2147,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
this.databaseBackend.updateConversation(conversation);
}
- public void reconnectAccount(final Account account, final boolean force) {
+ private void reconnectAccount(final Account account, final boolean force, final boolean interactive) {
synchronized (account) {
if (account.getXmppConnection() != null) {
disconnect(account, force);
@@ -2165,6 +2167,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
account.setXmppConnection(createConnection(account));
}
Thread thread = new Thread(account.getXmppConnection());
+ account.getXmppConnection().setInteractive(interactive);
thread.start();
scheduleWakeUpCall(Config.CONNECT_TIMEOUT, account.getUuid().hashCode());
} else {
@@ -2178,7 +2181,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
new Thread(new Runnable() {
@Override
public void run() {
- reconnectAccount(account,false);
+ reconnectAccount(account,false,true);
}
}).start();
}
diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
index a98ccd430..3a52cf36c 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
@@ -37,6 +37,7 @@ import android.widget.Toast;
import net.java.otr4j.session.SessionStatus;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.concurrent.ConcurrentLinkedQueue;
@@ -1226,6 +1227,48 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
updateSendButton();
}
+ private int completionIndex = 0;
+ private int lastCompletionLength = 0;
+ private String incomplete;
+ private int lastCompletionCursor;
+ private boolean firstWord = false;
+
+ @Override
+ public boolean onTabPressed(boolean repeated) {
+ if (conversation == null || conversation.getMode() == Conversation.MODE_SINGLE) {
+ return false;
+ }
+ if (repeated) {
+ completionIndex++;
+ } else {
+ lastCompletionLength = 0;
+ completionIndex = 0;
+ final String content = mEditMessage.getText().toString();
+ lastCompletionCursor = mEditMessage.getSelectionEnd();
+ int start = lastCompletionCursor > 0 ? content.lastIndexOf(" ",lastCompletionCursor-1) + 1 : 0;
+ firstWord = start == 0;
+ incomplete = content.substring(start,lastCompletionCursor);
+ }
+ List<String> completions = new ArrayList<>();
+ for(MucOptions.User user : conversation.getMucOptions().getUsers()) {
+ if (user.getName().startsWith(incomplete)) {
+ completions.add(user.getName()+(firstWord ? ": " : " "));
+ }
+ }
+ Collections.sort(completions);
+ if (completions.size() > completionIndex) {
+ String completion = completions.get(completionIndex).substring(incomplete.length());
+ mEditMessage.getEditableText().delete(lastCompletionCursor,lastCompletionCursor + lastCompletionLength);
+ mEditMessage.getEditableText().insert(lastCompletionCursor, completion);
+ lastCompletionLength = completion.length();
+ } else {
+ completionIndex = -1;
+ mEditMessage.getEditableText().delete(lastCompletionCursor,lastCompletionCursor + lastCompletionLength);
+ lastCompletionLength = 0;
+ }
+ return true;
+ }
+
@Override
public void onActivityResult(int requestCode, int resultCode,
final Intent data) {
diff --git a/src/main/java/eu/siacs/conversations/ui/EditMessage.java b/src/main/java/eu/siacs/conversations/ui/EditMessage.java
index 72975bb76..fc655b0ce 100644
--- a/src/main/java/eu/siacs/conversations/ui/EditMessage.java
+++ b/src/main/java/eu/siacs/conversations/ui/EditMessage.java
@@ -32,21 +32,32 @@ public class EditMessage extends EditText {
private boolean isUserTyping = false;
+ private boolean lastInputWasTab = false;
+
protected KeyboardListener keyboardListener;
@Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_ENTER && !event.isShiftPressed()) {
+ public boolean onKeyDown(int keyCode, KeyEvent e) {
+ if (keyCode == KeyEvent.KEYCODE_ENTER && !e.isShiftPressed()) {
+ lastInputWasTab = false;
if (keyboardListener != null && keyboardListener.onEnterPressed()) {
return true;
}
+ } else if (keyCode == KeyEvent.KEYCODE_TAB && !e.isAltPressed() && !e.isCtrlPressed()) {
+ if (keyboardListener != null && keyboardListener.onTabPressed(this.lastInputWasTab)) {
+ lastInputWasTab = true;
+ return true;
+ }
+ } else {
+ lastInputWasTab = false;
}
- return super.onKeyDown(keyCode, event);
+ return super.onKeyDown(keyCode, e);
}
@Override
public void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
super.onTextChanged(text,start,lengthBefore,lengthAfter);
+ lastInputWasTab = false;
if (this.mTypingHandler != null && this.keyboardListener != null) {
this.mTypingHandler.removeCallbacks(mTypingTimeout);
this.mTypingHandler.postDelayed(mTypingTimeout, Config.TYPING_TIMEOUT * 1000);
@@ -69,10 +80,11 @@ public class EditMessage extends EditText {
}
public interface KeyboardListener {
- public boolean onEnterPressed();
- public void onTypingStarted();
- public void onTypingStopped();
- public void onTextDeleted();
+ boolean onEnterPressed();
+ void onTypingStarted();
+ void onTypingStopped();
+ void onTextDeleted();
+ boolean onTabPressed(boolean repeated);
}
}
diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java
index a15079512..3bcbda439 100644
--- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java
+++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java
@@ -1,5 +1,6 @@
package eu.siacs.conversations.ui.adapter;
+import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@@ -324,7 +325,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
viewHolder.messageBody.setText("");
}
viewHolder.messageBody.setTextColor(this.getMessageTextColor(darkBackground, true));
- viewHolder.messageBody.setLinkTextColor(this.getMessageTextColor(darkBackground,true));
+ viewHolder.messageBody.setLinkTextColor(this.getMessageTextColor(darkBackground, true));
viewHolder.messageBody.setHighlightColor(activity.getResources().getColor(darkBackground ? R.color.grey800 : R.color.grey500));
viewHolder.messageBody.setTypeface(null, Typeface.NORMAL);
viewHolder.messageBody.setTextIsSelectable(true);
@@ -616,10 +617,14 @@ public class MessageAdapter extends ArrayAdapter<Message> {
PackageManager manager = activity.getPackageManager();
List<ResolveInfo> infos = manager.queryIntentActivities(openIntent, 0);
if (infos.size() > 0) {
- getContext().startActivity(openIntent);
- } else {
- Toast.makeText(activity,R.string.no_application_found_to_open_file,Toast.LENGTH_SHORT).show();
+ try {
+ getContext().startActivity(openIntent);
+ return;
+ } catch (ActivityNotFoundException e) {
+ //ignored
+ }
}
+ Toast.makeText(activity,R.string.no_application_found_to_open_file,Toast.LENGTH_SHORT).show();
}
public void showLocation(Message message) {
diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
index fd6465021..c41b69748 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
@@ -42,6 +42,7 @@ import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509TrustManager;
+import de.duenndns.ssl.MemorizingTrustManager;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.crypto.sasl.DigestMd5;
import eu.siacs.conversations.crypto.sasl.Plain;
@@ -100,6 +101,7 @@ public class XmppConnection implements Runnable {
private long lastPingSent = 0;
private long lastConnect = 0;
private long lastSessionStarted = 0;
+ private boolean mInteractive = false;
private int attempt = 0;
private final Hashtable<String, Pair<IqPacket, OnIqPacketReceived>> packetCallbacks = new Hashtable<>();
private OnPresencePacketReceived presenceListener = null;
@@ -515,9 +517,15 @@ public class XmppConnection implements Runnable {
tagReader.readTag();
try {
final SSLContext sc = SSLContext.getInstance("TLS");
- sc.init(null,new X509TrustManager[]{this.mXmppConnectionService.getMemorizingTrustManager()},mXmppConnectionService.getRNG());
+ MemorizingTrustManager trustManager = this.mXmppConnectionService.getMemorizingTrustManager();
+ sc.init(null,new X509TrustManager[]{mInteractive ? trustManager : trustManager.getNonInteractive()},mXmppConnectionService.getRNG());
final SSLSocketFactory factory = sc.getSocketFactory();
- final HostnameVerifier verifier = this.mXmppConnectionService.getMemorizingTrustManager().wrapHostnameVerifier(new StrictHostnameVerifier());
+ final HostnameVerifier verifier;
+ if (mInteractive) {
+ verifier = trustManager.wrapHostnameVerifier(new StrictHostnameVerifier());
+ } else {
+ verifier = trustManager.wrapHostnameVerifierNonInteractive(new StrictHostnameVerifier());
+ }
final InetAddress address = socket == null ? null : socket.getInetAddress();
if (factory == null || address == null || verifier == null) {
@@ -839,7 +847,7 @@ public class XmppConnection implements Runnable {
sendEnableCarbons();
}
if (getFeatures().blocking() && !features.blockListRequested) {
- Log.d(Config.LOGTAG,account.getJid().toBareJid()+": Requesting block list");
+ Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": Requesting block list");
this.sendIqPacket(getIqGenerator().generateGetBlockList(), mXmppConnectionService.getIqParser());
}
}
@@ -949,7 +957,6 @@ public class XmppConnection implements Runnable {
disconnect(true);
return;
}
- final String name = packet.getName();
tagWriter.writeStanzaAsync(packet);
if (packet instanceof AbstractAcknowledgeableStanza) {
AbstractAcknowledgeableStanza stanza = (AbstractAcknowledgeableStanza) packet;
@@ -965,9 +972,7 @@ public class XmppConnection implements Runnable {
}
public void sendPing() {
- if (streamFeatures.hasChild("sm")) {
- tagWriter.writeStanzaAsync(new RequestPacket(smVersion));
- } else {
+ if (!r()) {
final IqPacket iq = new IqPacket(IqPacket.TYPE.GET);
iq.setFrom(account.getJid());
iq.addChild("ping", "urn:xmpp:ping");
@@ -1078,8 +1083,13 @@ public class XmppConnection implements Runnable {
return null;
}
- public void r() {
- this.tagWriter.writeStanzaAsync(new RequestPacket(smVersion));
+ public boolean r() {
+ if (getFeatures().sm()) {
+ this.tagWriter.writeStanzaAsync(new RequestPacket(smVersion));
+ return true;
+ } else {
+ return false;
+ }
}
public String getMucServer() {
@@ -1138,6 +1148,10 @@ public class XmppConnection implements Runnable {
this.lastConnect = 0;
}
+ public void setInteractive(boolean interactive) {
+ this.mInteractive = interactive;
+ }
+
private class Info {
public final ArrayList<String> features = new ArrayList<>();
public final ArrayList<Pair<String,String>> identities = new ArrayList<>();
diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java
index 85280c5ce..0b0cb4083 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java
@@ -176,6 +176,7 @@ public class JingleInbandTransport extends JingleTransport {
data.setAttribute("sid", this.sessionId);
data.setContent(base64);
this.account.getXmppConnection().sendIqPacket(iq, this.onAckReceived);
+ this.account.getXmppConnection().r(); //don't fill up stanza queue too much
this.seq++;
if (this.remainingSize > 0) {
connection.updateProgress((int) ((((double) (this.fileSize - this.remainingSize)) / this.fileSize) * 100));