aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/XEPs.md1
-rw-r--r--libs/MemorizingTrustManager/src/de/duenndns/ssl/MemorizingTrustManager.java2
-rw-r--r--src/main/java/eu/siacs/conversations/Config.java2
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Contact.java55
-rw-r--r--src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java5
-rw-r--r--src/main/java/eu/siacs/conversations/parser/AbstractParser.java47
-rw-r--r--src/main/java/eu/siacs/conversations/parser/IqParser.java5
-rw-r--r--src/main/java/eu/siacs/conversations/parser/MessageParser.java13
-rw-r--r--src/main/java/eu/siacs/conversations/parser/PresenceParser.java16
-rw-r--r--src/main/java/eu/siacs/conversations/services/XmppConnectionService.java39
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java28
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ConversationActivity.java2
-rw-r--r--src/main/java/eu/siacs/conversations/ui/SettingsActivity.java3
-rw-r--r--src/main/java/eu/siacs/conversations/ui/XmppActivity.java2
-rw-r--r--src/main/java/eu/siacs/conversations/utils/UIHelper.java8
-rw-r--r--src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java3
-rw-r--r--src/main/java/eu/siacs/conversations/xmpp/stanzas/MessagePacket.java2
-rw-r--r--src/main/res/values/strings.xml3
-rw-r--r--src/main/res/xml/preferences.xml5
19 files changed, 157 insertions, 84 deletions
diff --git a/docs/XEPs.md b/docs/XEPs.md
index 873ea998c..48ce48150 100644
--- a/docs/XEPs.md
+++ b/docs/XEPs.md
@@ -19,6 +19,7 @@
* XEP-0280: Message Carbons
* XEP-0308: Last Message Correction
* XEP-0313: Message Archive Management
+* XEP-0319: Last User Interaction in Presence
* XEP-0333: Chat Markers
* XEP-0352: Client State Indication
* XEP-0357: Push Notifications
diff --git a/libs/MemorizingTrustManager/src/de/duenndns/ssl/MemorizingTrustManager.java b/libs/MemorizingTrustManager/src/de/duenndns/ssl/MemorizingTrustManager.java
index 547328f1f..d1a7e341a 100644
--- a/libs/MemorizingTrustManager/src/de/duenndns/ssl/MemorizingTrustManager.java
+++ b/libs/MemorizingTrustManager/src/de/duenndns/ssl/MemorizingTrustManager.java
@@ -706,7 +706,7 @@ public class MemorizingTrustManager implements X509TrustManager {
}
@Override
public boolean verify(String hostname, SSLSession session) {
- return verify(hostname, session, true);
+ return verify(hostname, session, false);
}
diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java
index 68ad2c122..6bc7a0a04 100644
--- a/src/main/java/eu/siacs/conversations/Config.java
+++ b/src/main/java/eu/siacs/conversations/Config.java
@@ -97,7 +97,7 @@ public final class Config {
public static final boolean DISABLE_HTTP_UPLOAD = false;
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 boolean BACKGROUND_STANZA_LOGGING = false;
+ public static final boolean BACKGROUND_STANZA_LOGGING = false; //log all stanzas that were received while the app is in background
public static final boolean RESET_ATTEMPT_COUNT_ON_NETWORK_CHANGE = true; //setting to true might increase power consumption
public static final boolean ENCRYPT_ON_HTTP_UPLOADED = false;
diff --git a/src/main/java/eu/siacs/conversations/entities/Contact.java b/src/main/java/eu/siacs/conversations/entities/Contact.java
index 8721d9c46..70878a734 100644
--- a/src/main/java/eu/siacs/conversations/entities/Contact.java
+++ b/src/main/java/eu/siacs/conversations/entities/Contact.java
@@ -34,7 +34,6 @@ public class Contact implements ListItem, Blockable {
public static final String LAST_PRESENCE = "last_presence";
public static final String LAST_TIME = "last_time";
public static final String GROUPS = "groups";
- public Lastseen lastseen = new Lastseen();
protected String accountUuid;
protected String systemName;
protected String serverName;
@@ -50,9 +49,14 @@ public class Contact implements ListItem, Blockable {
protected Account account;
protected Avatar avatar;
+ private boolean mActive = false;
+ private long mLastseen = 0;
+ private String mLastPresence = null;
+
public Contact(final String account, final String systemName, final String serverName,
final Jid jid, final int subscription, final String photoUri,
- final String systemAccount, final String keys, final String avatar, final Lastseen lastseen, final String groups) {
+ final String systemAccount, final String keys, final String avatar, final long lastseen,
+ final String presence, final String groups) {
this.accountUuid = account;
this.systemName = systemName;
this.serverName = serverName;
@@ -75,7 +79,8 @@ public class Contact implements ListItem, Blockable {
} catch (JSONException e) {
this.groups = new JSONArray();
}
- this.lastseen = lastseen;
+ this.mLastseen = lastseen;
+ this.mLastPresence = presence;
}
public Contact(final Jid jid) {
@@ -83,9 +88,6 @@ public class Contact implements ListItem, Blockable {
}
public static Contact fromCursor(final Cursor cursor) {
- final Lastseen lastseen = new Lastseen(
- cursor.getString(cursor.getColumnIndex(LAST_PRESENCE)),
- cursor.getLong(cursor.getColumnIndex(LAST_TIME)));
final Jid jid;
try {
jid = Jid.fromString(cursor.getString(cursor.getColumnIndex(JID)), true);
@@ -102,7 +104,8 @@ public class Contact implements ListItem, Blockable {
cursor.getString(cursor.getColumnIndex(SYSTEMACCOUNT)),
cursor.getString(cursor.getColumnIndex(KEYS)),
cursor.getString(cursor.getColumnIndex(AVATAR)),
- lastseen,
+ cursor.getLong(cursor.getColumnIndex(LAST_TIME)),
+ cursor.getString(cursor.getColumnIndex(LAST_PRESENCE)),
cursor.getString(cursor.getColumnIndex(GROUPS)));
}
@@ -197,8 +200,8 @@ public class Contact implements ListItem, Blockable {
values.put(PHOTOURI, photoUri);
values.put(KEYS, keys.toString());
values.put(AVATAR, avatar == null ? null : avatar.getFilename());
- values.put(LAST_PRESENCE, lastseen.presence);
- values.put(LAST_TIME, lastseen.time);
+ values.put(LAST_PRESENCE, mLastPresence);
+ values.put(LAST_TIME, mLastseen);
values.put(GROUPS, groups.toString());
return values;
}
@@ -517,18 +520,32 @@ public class Contact implements ListItem, Blockable {
this.commonName = cn;
}
- public static class Lastseen {
- public long time;
- public String presence;
+ public void flagActive() {
+ this.mActive = true;
+ }
- public Lastseen() {
- this(null, 0);
- }
+ public void flagInactive() {
+ this.mActive = false;
+ }
- public Lastseen(final String presence, final long time) {
- this.presence = presence;
- this.time = time;
- }
+ public boolean isActive() {
+ return this.mActive;
+ }
+
+ public void setLastseen(long timestamp) {
+ this.mLastseen = Math.max(timestamp, mLastseen);
+ }
+
+ public long getLastseen() {
+ return this.mLastseen;
+ }
+
+ public void setLastPresence(String presence) {
+ this.mLastPresence = presence;
+ }
+
+ public String getLastPresence() {
+ return this.mLastPresence;
}
public final class Options {
diff --git a/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java b/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java
index 64bd5e50e..765e91f29 100644
--- a/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java
+++ b/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java
@@ -31,7 +31,8 @@ public abstract class AbstractGenerator {
"http://jabber.org/protocol/nick+notify",
"urn:xmpp:ping",
"jabber:iq:version",
- "http://jabber.org/protocol/chatstates"};
+ "http://jabber.org/protocol/chatstates"
+ };
private final String[] MESSAGE_CONFIRMATION_FEATURES = {
"urn:xmpp:chat-markers:0",
"urn:xmpp:receipts"
@@ -45,7 +46,7 @@ public abstract class AbstractGenerator {
protected final String IDENTITY_NAME = "Pix-Art Messenger";
protected final String IDENTITY_TYPE = "phone";
- private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
+ private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
protected XmppConnectionService mXmppConnectionService;
diff --git a/src/main/java/eu/siacs/conversations/parser/AbstractParser.java b/src/main/java/eu/siacs/conversations/parser/AbstractParser.java
index c14a7eb0d..4699d2868 100644
--- a/src/main/java/eu/siacs/conversations/parser/AbstractParser.java
+++ b/src/main/java/eu/siacs/conversations/parser/AbstractParser.java
@@ -1,9 +1,7 @@
package eu.siacs.conversations.parser;
-
import java.text.ParseException;
import java.text.SimpleDateFormat;
-import java.util.Date;
import java.util.Locale;
import eu.siacs.conversations.entities.Account;
@@ -14,7 +12,6 @@ import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
import eu.siacs.conversations.xmpp.jid.Jid;
-import eu.siacs.conversations.xmpp.stanzas.AbstractStanza;
public abstract class AbstractParser {
@@ -24,46 +21,48 @@ public abstract class AbstractParser {
this.mXmppConnectionService = service;
}
- public static Long getTimestamp(Element element, Long defaultValue) {
+ public static Long parseTimestamp(Element element, Long d) {
Element delay = element.findChild("delay","urn:xmpp:delay");
if (delay != null) {
String stamp = delay.getAttribute("stamp");
if (stamp != null) {
try {
- return AbstractParser.parseTimestamp(delay.getAttribute("stamp")).getTime();
+ return AbstractParser.parseTimestamp(delay.getAttribute("stamp"));
} catch (ParseException e) {
- return defaultValue;
+ return d;
}
}
}
- return defaultValue;
+ return d;
}
- protected long getTimestamp(Element packet) {
- return getTimestamp(packet,System.currentTimeMillis());
+ public static long parseTimestamp(Element element) {
+ return parseTimestamp(element, System.currentTimeMillis());
}
- public static Date parseTimestamp(String timestamp) throws ParseException {
+ public static long parseTimestamp(String timestamp) throws ParseException {
timestamp = timestamp.replace("Z", "+0000");
SimpleDateFormat dateFormat;
+ long ms;
+ if (timestamp.charAt(19) == '.' && timestamp.length() >= 25) {
+ String millis = timestamp.substring(19,timestamp.length() - 5);
+ try {
+ double fractions = Double.parseDouble("0" + millis);
+ ms = Math.round(1000 * fractions);
+ } catch (NumberFormatException e) {
+ ms = 0;
+ }
+ } else {
+ ms = 0;
+ }
timestamp = timestamp.substring(0,19)+timestamp.substring(timestamp.length() -5,timestamp.length());
dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ",Locale.US);
- return dateFormat.parse(timestamp);
+ return Math.min(dateFormat.parse(timestamp).getTime()+ms, System.currentTimeMillis());
}
- protected void updateLastseen(final AbstractStanza packet, final Account account, final boolean presenceOverwrite) {
- updateLastseen(getTimestamp(packet), account, packet.getFrom(), presenceOverwrite);
- }
-
- protected void updateLastseen(long timestamp, final Account account, final Jid from, final boolean presenceOverwrite) {
- final String presence = from == null || from.isBareJid() ? "" : from.getResourcepart();
- final Contact contact = account.getRoster().getContact(from);
- if (timestamp >= contact.lastseen.time) {
- contact.lastseen.time = timestamp;
- if (!presence.isEmpty() && presenceOverwrite) {
- contact.lastseen.presence = presence;
- }
- }
+ protected void updateLastseen(final Account account, final Jid from) {
+ final Contact contact = account.getRoster().getContact(from);
+ contact.setLastPresence(from.isBareJid() ? "" : from.getResourcepart());
}
protected String avatarData(Element items) {
diff --git a/src/main/java/eu/siacs/conversations/parser/IqParser.java b/src/main/java/eu/siacs/conversations/parser/IqParser.java
index 189df4a7b..06d4e37e0 100644
--- a/src/main/java/eu/siacs/conversations/parser/IqParser.java
+++ b/src/main/java/eu/siacs/conversations/parser/IqParser.java
@@ -277,11 +277,6 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
@Override
public void onIqPacketReceived(final Account account, final IqPacket packet) {
- if (Config.BACKGROUND_STANZA_LOGGING && (packet.getType() == IqPacket.TYPE.GET || packet.getType() == IqPacket.TYPE.SET)) {
- Element first = packet.getChildren().size() > 0 ? packet.getChildren().get(0) : null;
- Log.d(Config.LOGTAG,account.getJid().toBareJid()+": IQ request from "+packet.getFrom()+(first == null ? "" : " "+first));
- }
-
if (packet.getType() == IqPacket.TYPE.ERROR || packet.getType() == IqPacket.TYPE.TIMEOUT) {
return;
} else if (packet.hasChild("query", Xmlns.ROSTER) && packet.fromServer(account)) {
diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java
index 887b9124a..354128f0b 100644
--- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java
+++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java
@@ -7,6 +7,7 @@ import android.util.Pair;
import net.java.otr4j.session.Session;
import net.java.otr4j.session.SessionStatus;
+import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
@@ -31,6 +32,7 @@ import eu.siacs.conversations.http.HttpConnectionManager;
import eu.siacs.conversations.services.MessageArchiveService;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.utils.CryptoHelper;
+import eu.siacs.conversations.utils.Xmlns;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xmpp.OnMessagePacketReceived;
import eu.siacs.conversations.xmpp.chatstate.ChatState;
@@ -327,7 +329,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
}
if (timestamp == null) {
- timestamp = AbstractParser.getTimestamp(packet, System.currentTimeMillis());
+ timestamp = AbstractParser.parseTimestamp(packet);
}
final String body = packet.getBody();
final Element mucUserElement = packet.findChild("x", "http://jabber.org/protocol/muc#user");
@@ -434,14 +436,11 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
if (conversationMultiMode) {
Jid trueCounterpart = conversation.getMucOptions().getTrueCounterpart(counterpart);
message.setTrueCounterpart(trueCounterpart);
- if (trueCounterpart != null) {
- updateLastseen(timestamp, account, trueCounterpart, false);
- }
if (!isTypeGroupChat) {
message.setType(Message.TYPE_PRIVATE);
}
} else {
- updateLastseen(timestamp, account, packet.getFrom(), true);
+ updateLastseen(account, from);
}
if (replacementId != null && mXmppConnectionService.allowMessageCorrection()) {
@@ -538,9 +537,6 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
}
}
} else if (!packet.hasChild("body")){ //no body
- if (Config.BACKGROUND_STANZA_LOGGING && mXmppConnectionService.checkListeners()) {
- Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": " + packet+ " (carbon="+Boolean.toString(isCarbon)+")");
- }
Conversation conversation = mXmppConnectionService.find(account, from.toBareJid());
if (isTypeGroupChat) {
if (packet.hasChild("subject")) {
@@ -603,7 +599,6 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
mXmppConnectionService.markRead(conversation);
}
} else {
- updateLastseen(timestamp, account, packet.getFrom(), true);
final Message displayedMessage = mXmppConnectionService.markMessage(account, from.toBareJid(), displayed.getAttribute("id"), Message.STATUS_SEND_DISPLAYED);
Message message = displayedMessage == null ? null : displayedMessage.prev();
while (message != null
diff --git a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java
index 89f294e90..30732fd2d 100644
--- a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java
+++ b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java
@@ -2,6 +2,7 @@ package eu.siacs.conversations.parser;
import android.util.Log;
+import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
@@ -205,6 +206,20 @@ public class PresenceParser extends AbstractParser implements
mXmppConnectionService.fetchCaps(account, from, presence);
}
+ final Element idle = packet.findChild("idle","urn:xmpp:idle:1");
+ if (idle != null) {
+ contact.flagInactive();
+ String since = idle.getAttribute("since");
+ try {
+ contact.setLastseen(AbstractParser.parseTimestamp(since));
+ } catch (NullPointerException | ParseException e) {
+ contact.setLastseen(System.currentTimeMillis());
+ }
+ } else {
+ contact.flagActive();
+ contact.setLastseen(AbstractParser.parseTimestamp(packet));
+ }
+
PgpEngine pgp = mXmppConnectionService.getPgpEngine();
Element x = packet.findChild("x", "jabber:x:signed");
if (pgp != null && x != null) {
@@ -213,7 +228,6 @@ public class PresenceParser extends AbstractParser implements
contact.setPgpKeyId(pgp.fetchKeyId(account, msg, x.getContent()));
}
boolean online = sizeBefore < contact.getPresences().size();
- updateLastseen(packet, account, false);
mXmppConnectionService.onContactStatusChanged.onContactStatusChanged(contact, online);
} else if (type.equals("unavailable")) {
if (from.isBareJid()) {
diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
index 84eeeeef2..c2f1810a5 100644
--- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
+++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
@@ -79,6 +79,7 @@ import eu.siacs.conversations.entities.Roster;
import eu.siacs.conversations.entities.ServiceDiscoveryResult;
import eu.siacs.conversations.entities.Transferable;
import eu.siacs.conversations.entities.TransferablePlaceholder;
+import eu.siacs.conversations.generator.AbstractGenerator;
import eu.siacs.conversations.generator.IqGenerator;
import eu.siacs.conversations.generator.MessageGenerator;
import eu.siacs.conversations.generator.PresenceGenerator;
@@ -140,6 +141,9 @@ public class XmppConnectionService extends Service {
private final List<Conversation> conversations = new CopyOnWriteArrayList<>();
private final IqGenerator mIqGenerator = new IqGenerator(this);
private final List<String> mInProgressAvatarFetches = new ArrayList<>();
+
+ private long mLastActivity = 0;
+
public DatabaseBackend databaseBackend;
private ContentObserver contactObserver = new ContentObserver(null) {
@Override
@@ -1578,6 +1582,7 @@ public class XmppConnectionService extends Service {
public void setOnConversationListChangedListener(OnConversationUpdate listener) {
synchronized (this) {
+ this.mLastActivity = System.currentTimeMillis();
if (checkListeners()) {
switchToForeground();
}
@@ -1790,15 +1795,21 @@ public class XmppConnectionService extends Service {
}
private void switchToForeground() {
+ final boolean broadcastLastActivity = broadcastLastActivity();
for (Conversation conversation : getConversations()) {
conversation.setIncomingChatState(ChatState.ACTIVE);
}
for (Account account : getAccounts()) {
if (account.getStatus() == Account.State.ONLINE) {
account.deactivateGracePeriod();
- XmppConnection connection = account.getXmppConnection();
- if (connection != null && connection.getFeatures().csi()) {
- connection.sendActive();
+ final XmppConnection connection = account.getXmppConnection();
+ if (connection != null ) {
+ if (connection.getFeatures().csi()) {
+ connection.sendActive();
+ }
+ if (broadcastLastActivity) {
+ sendPresence(account, false); //send new presence but don't include idle because we are not
+ }
}
}
}
@@ -1806,10 +1817,14 @@ public class XmppConnectionService extends Service {
}
private void switchToBackground() {
+ final boolean broadcastLastActivity = broadcastLastActivity();
for (Account account : getAccounts()) {
if (account.getStatus() == Account.State.ONLINE) {
XmppConnection connection = account.getXmppConnection();
if (connection != null) {
+ if (broadcastLastActivity) {
+ sendPresence(account, broadcastLastActivity);
+ }
if (connection.getFeatures().csi()) {
connection.sendInactive();
}
@@ -2247,6 +2262,7 @@ public class XmppConnectionService extends Service {
private void disconnect(Account account, boolean force) {
if ((account.getStatus() == Account.State.ONLINE)
|| (account.getStatus() == Account.State.DISABLED)) {
+ final XmppConnection connection = account.getXmppConnection();
if (!force) {
List<Conversation> conversations = getConversations();
for (Conversation conversation : conversations) {
@@ -2264,7 +2280,7 @@ public class XmppConnectionService extends Service {
}
sendOfflinePresence(account);
}
- account.getXmppConnection().disconnect(force);
+ connection.disconnect(force);
}
}
@@ -2808,6 +2824,10 @@ public class XmppConnectionService extends Service {
return getPreferences().getBoolean("show_connection_options", false);
}
+ public boolean broadcastLastActivity() {
+ return getPreferences().getBoolean("last_activity", false);
+ }
+
public int unreadCount() {
int count = 0;
for (Conversation conversation : getConversations()) {
@@ -3046,6 +3066,10 @@ public class XmppConnectionService extends Service {
}
public void sendPresence(final Account account) {
+ sendPresence(account, checkListeners() && broadcastLastActivity());
+ }
+
+ private void sendPresence(final Account account, final boolean includeIdleTimestamp) {
PresencePacket packet;
if (manuallyChangePresence()) {
packet = mPresenceGenerator.selfPresence(account, account.getPresenceStatus());
@@ -3056,6 +3080,10 @@ public class XmppConnectionService extends Service {
} else {
packet = mPresenceGenerator.selfPresence(account, getTargetPresence());
}
+ if (mLastActivity > 0 && includeIdleTimestamp) {
+ long since = Math.min(mLastActivity, System.currentTimeMillis()); //don't send future dates
+ packet.addChild("idle","urn:xmpp:idle:1").setAttribute("since", AbstractGenerator.getTimestamp(since));
+ }
sendPresencePacket(account, packet);
}
@@ -3066,9 +3094,10 @@ public class XmppConnectionService extends Service {
}
public void refreshAllPresences() {
+ boolean includeIdleTimestamp = checkListeners() && broadcastLastActivity();
for (Account account : getAccounts()) {
if (!account.isOptionSet(Account.OPTION_DISABLED)) {
- sendPresence(account);
+ sendPresence(account, includeIdleTimestamp);
}
}
}
diff --git a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java
index 4f2f5e7b2..1e73fc68b 100644
--- a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java
@@ -106,10 +106,10 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
}
};
private Jid accountJid;
+ private TextView lastseen;
private Jid contactJid;
private TextView contactJidTv;
private TextView accountJidTv;
- private TextView lastseen;
private TextView statusMessage;
private CheckBox send;
private CheckBox receive;
@@ -117,7 +117,8 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
private QuickContactBadge badge;
private LinearLayout keys;
private LinearLayout tags;
- private boolean showDynamicTags;
+ private boolean showDynamicTags = false;
+ private boolean showLastSeen = false;
private String messageFingerprint;
private DialogInterface.OnClickListener addToPhonebook = new DialogInterface.OnClickListener() {
@@ -206,7 +207,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
contactJidTv = (TextView) findViewById(R.id.details_contactjid);
accountJidTv = (TextView) findViewById(R.id.details_account);
- lastseen = (TextView) findViewById(R.id.details_lastseen);
+ lastseen = (TextView) findViewById(R.id.details_lastseen);
statusMessage = (TextView) findViewById(R.id.status_message);
send = (CheckBox) findViewById(R.id.details_send_presence);
receive = (CheckBox) findViewById(R.id.details_receive_presence);
@@ -224,9 +225,14 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
getActionBar().setHomeButtonEnabled(true);
getActionBar().setDisplayHomeAsUpEnabled(true);
}
+ }
+ @Override
+ public void onStart() {
+ super.onStart();
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
this.showDynamicTags = preferences.getBoolean("show_dynamic_tags",false);
+ this.showLastSeen = preferences.getBoolean("last_activity", true);
}
private void share() {
@@ -390,11 +396,17 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
statusMessage.setVisibility(View.GONE);
}
- if (contact.isBlocked() && !this.showDynamicTags) {
- lastseen.setText(R.string.contact_blocked);
- } else {
- lastseen.setText(UIHelper.lastseen(getApplicationContext(), contact.lastseen.time));
- }
+ if (contact.isBlocked() && !this.showDynamicTags) {
+ lastseen.setVisibility(View.VISIBLE);
+ lastseen.setText(R.string.contact_blocked);
+ } else {
+ if (showLastSeen && contact.getLastseen() > 0) {
+ lastseen.setVisibility(View.VISIBLE);
+ lastseen.setText(UIHelper.lastseen(getApplicationContext(), contact.isActive(), contact.getLastseen()));
+ } else {
+ lastseen.setVisibility(View.GONE);
+ }
+ }
if (contact.getPresences().size() > 1) {
contactJidTv.setText(contact.getDisplayJid() + " ("
diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java
index 4d9aa8d6c..a2c58da6e 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java
@@ -1144,7 +1144,7 @@ public class ConversationActivity extends XmppActivity
upKey = KeyEvent.KEYCODE_DPAD_UP;
downKey = KeyEvent.KEYCODE_DPAD_DOWN;
}
- final boolean modifier = event.isCtrlPressed() || event.isAltPressed();
+ final boolean modifier = event.isCtrlPressed() || (event.getMetaState() & KeyEvent.META_ALT_LEFT_ON) != 0;
if (modifier && key == KeyEvent.KEYCODE_TAB && isConversationsOverviewHideable()) {
toggleConversationsOverview();
return true;
diff --git a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java
index 30781e553..0972c103c 100644
--- a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java
@@ -161,7 +161,8 @@ public class SettingsActivity extends XmppActivity implements
"away_when_screen_off",
"allow_message_correction",
"treat_vibrate_as_silent",
- "manually_change_presence");
+ "manually_change_presence",
+ "last_activity");
if (name.equals("resource")) {
String resource = preferences.getString("resource", "mobile")
.toLowerCase(Locale.US);
diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
index ad1cbf905..f7e18e66c 100644
--- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
@@ -923,7 +923,7 @@ public abstract class XmppActivity extends Activity {
final String[] presencesArray = presences.asStringArray();
int preselectedPresence = 0;
for (int i = 0; i < presencesArray.length; ++i) {
- if (presencesArray[i].equals(contact.lastseen.presence)) {
+ if (presencesArray[i].equals(contact.getLastPresence())) {
preselectedPresence = i;
break;
}
diff --git a/src/main/java/eu/siacs/conversations/utils/UIHelper.java b/src/main/java/eu/siacs/conversations/utils/UIHelper.java
index 4ab748188..acc7f28c5 100644
--- a/src/main/java/eu/siacs/conversations/utils/UIHelper.java
+++ b/src/main/java/eu/siacs/conversations/utils/UIHelper.java
@@ -107,12 +107,10 @@ public class UIHelper {
.get(Calendar.DAY_OF_YEAR);
}
- public static String lastseen(Context context, long time) {
- if (time == 0) {
- return context.getString(R.string.never_seen);
- }
+ public static String lastseen(Context context, boolean active, long time) {
long difference = (System.currentTimeMillis() - time) / 1000;
- if (difference < 60) {
+ active = active && difference <= 300;
+ if (active || difference < 60) {
return context.getString(R.string.last_seen_now);
} else if (difference < 60 * 2) {
return context.getString(R.string.last_seen_min);
diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
index bd570d82e..42dc2989c 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
@@ -650,6 +650,9 @@ public class XmppConnection implements Runnable {
}
++stanzasReceived;
lastPacketReceived = SystemClock.elapsedRealtime();
+ if (Config.BACKGROUND_STANZA_LOGGING && mXmppConnectionService.checkListeners()) {
+ Log.d(Config.LOGTAG,"[background stanza] "+element);
+ }
return element;
}
diff --git a/src/main/java/eu/siacs/conversations/xmpp/stanzas/MessagePacket.java b/src/main/java/eu/siacs/conversations/xmpp/stanzas/MessagePacket.java
index 941b4b5f6..ac75a5e59 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/stanzas/MessagePacket.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/stanzas/MessagePacket.java
@@ -83,7 +83,7 @@ public class MessagePacket extends AbstractAcknowledgeableStanza {
if (packet == null) {
return null;
}
- Long timestamp = AbstractParser.getTimestamp(forwarded,null);
+ Long timestamp = AbstractParser.parseTimestamp(forwarded, null);
return new Pair(packet,timestamp);
}
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index 09d77ed3d..2ca2cc503 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -656,4 +656,7 @@
<string name="gp_short">Short</string>
<string name="gp_medium">Medium</string>
<string name="gp_long">Long</string>
+ <string name="pref_broadcast_last_activity">Broadcast Last User Interaction</string>
+ <string name="pref_broadcast_last_activity_summary">Let all your contacts know when use Conversations</string>
+ <string name="pref_privacy">Privacy</string>
</resources>
diff --git a/src/main/res/xml/preferences.xml b/src/main/res/xml/preferences.xml
index ed117866f..6897d6f15 100644
--- a/src/main/res/xml/preferences.xml
+++ b/src/main/res/xml/preferences.xml
@@ -164,6 +164,11 @@
android:title="@string/pref_use_indicate_received" />
<CheckBoxPreference
android:defaultValue="true"
+ android:key="last_activity"
+ android:title="@string/pref_broadcast_last_activity"
+ android:summary="@string/pref_broadcast_last_activity_summary"/>
+ <CheckBoxPreference
+ android:defaultValue="true"
android:key="crashreport"
android:summary="@string/pref_send_crash_summary"
android:title="@string/pref_send_crash" />