opt-in to send last userinteraction in presence
This commit is contained in:
parent
6639d0f23b
commit
71e9117176
|
@ -19,6 +19,7 @@
|
||||||
* XEP-0280: Message Carbons
|
* XEP-0280: Message Carbons
|
||||||
* XEP-0308: Last Message Correction
|
* XEP-0308: Last Message Correction
|
||||||
* XEP-0313: Message Archive Management
|
* XEP-0313: Message Archive Management
|
||||||
|
* XEP-0319: Last User Interaction in Presence
|
||||||
* XEP-0333: Chat Markers
|
* XEP-0333: Chat Markers
|
||||||
* XEP-0352: Client State Indication
|
* XEP-0352: Client State Indication
|
||||||
* XEP-0357: Push Notifications
|
* XEP-0357: Push Notifications
|
||||||
|
|
|
@ -34,7 +34,6 @@ public class Contact implements ListItem, Blockable {
|
||||||
public static final String LAST_PRESENCE = "last_presence";
|
public static final String LAST_PRESENCE = "last_presence";
|
||||||
public static final String LAST_TIME = "last_time";
|
public static final String LAST_TIME = "last_time";
|
||||||
public static final String GROUPS = "groups";
|
public static final String GROUPS = "groups";
|
||||||
public Lastseen lastseen = new Lastseen();
|
|
||||||
protected String accountUuid;
|
protected String accountUuid;
|
||||||
protected String systemName;
|
protected String systemName;
|
||||||
protected String serverName;
|
protected String serverName;
|
||||||
|
@ -50,9 +49,14 @@ public class Contact implements ListItem, Blockable {
|
||||||
protected Account account;
|
protected Account account;
|
||||||
protected Avatar avatar;
|
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,
|
public Contact(final String account, final String systemName, final String serverName,
|
||||||
final Jid jid, final int subscription, final String photoUri,
|
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.accountUuid = account;
|
||||||
this.systemName = systemName;
|
this.systemName = systemName;
|
||||||
this.serverName = serverName;
|
this.serverName = serverName;
|
||||||
|
@ -75,7 +79,8 @@ public class Contact implements ListItem, Blockable {
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
this.groups = new JSONArray();
|
this.groups = new JSONArray();
|
||||||
}
|
}
|
||||||
this.lastseen = lastseen;
|
this.mLastseen = lastseen;
|
||||||
|
this.mLastPresence = presence;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Contact(final Jid jid) {
|
public Contact(final Jid jid) {
|
||||||
|
@ -83,9 +88,6 @@ public class Contact implements ListItem, Blockable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Contact fromCursor(final Cursor cursor) {
|
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;
|
final Jid jid;
|
||||||
try {
|
try {
|
||||||
jid = Jid.fromString(cursor.getString(cursor.getColumnIndex(JID)), true);
|
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(SYSTEMACCOUNT)),
|
||||||
cursor.getString(cursor.getColumnIndex(KEYS)),
|
cursor.getString(cursor.getColumnIndex(KEYS)),
|
||||||
cursor.getString(cursor.getColumnIndex(AVATAR)),
|
cursor.getString(cursor.getColumnIndex(AVATAR)),
|
||||||
lastseen,
|
cursor.getLong(cursor.getColumnIndex(LAST_TIME)),
|
||||||
|
cursor.getString(cursor.getColumnIndex(LAST_PRESENCE)),
|
||||||
cursor.getString(cursor.getColumnIndex(GROUPS)));
|
cursor.getString(cursor.getColumnIndex(GROUPS)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,8 +200,8 @@ public class Contact implements ListItem, Blockable {
|
||||||
values.put(PHOTOURI, photoUri);
|
values.put(PHOTOURI, photoUri);
|
||||||
values.put(KEYS, keys.toString());
|
values.put(KEYS, keys.toString());
|
||||||
values.put(AVATAR, avatar == null ? null : avatar.getFilename());
|
values.put(AVATAR, avatar == null ? null : avatar.getFilename());
|
||||||
values.put(LAST_PRESENCE, lastseen.presence);
|
values.put(LAST_PRESENCE, mLastPresence);
|
||||||
values.put(LAST_TIME, lastseen.time);
|
values.put(LAST_TIME, mLastseen);
|
||||||
values.put(GROUPS, groups.toString());
|
values.put(GROUPS, groups.toString());
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
@ -517,18 +520,32 @@ public class Contact implements ListItem, Blockable {
|
||||||
this.commonName = cn;
|
this.commonName = cn;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Lastseen {
|
public void flagActive() {
|
||||||
public long time;
|
this.mActive = true;
|
||||||
public String presence;
|
}
|
||||||
|
|
||||||
public Lastseen() {
|
public void flagInactive() {
|
||||||
this(null, 0);
|
this.mActive = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Lastseen(final String presence, final long time) {
|
public boolean isActive() {
|
||||||
this.presence = presence;
|
return this.mActive;
|
||||||
this.time = time;
|
}
|
||||||
}
|
|
||||||
|
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 {
|
public final class Options {
|
||||||
|
|
|
@ -16,8 +16,6 @@ import eu.siacs.conversations.Config;
|
||||||
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
|
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
|
||||||
import eu.siacs.conversations.services.XmppConnectionService;
|
import eu.siacs.conversations.services.XmppConnectionService;
|
||||||
import eu.siacs.conversations.utils.PhoneHelper;
|
import eu.siacs.conversations.utils.PhoneHelper;
|
||||||
import eu.siacs.conversations.xmpp.jid.Jid;
|
|
||||||
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
|
|
||||||
|
|
||||||
public abstract class AbstractGenerator {
|
public abstract class AbstractGenerator {
|
||||||
private final String[] FEATURES = {
|
private final String[] FEATURES = {
|
||||||
|
@ -33,7 +31,8 @@ public abstract class AbstractGenerator {
|
||||||
"http://jabber.org/protocol/nick+notify",
|
"http://jabber.org/protocol/nick+notify",
|
||||||
"urn:xmpp:ping",
|
"urn:xmpp:ping",
|
||||||
"jabber:iq:version",
|
"jabber:iq:version",
|
||||||
"http://jabber.org/protocol/chatstates"};
|
"http://jabber.org/protocol/chatstates"
|
||||||
|
};
|
||||||
private final String[] MESSAGE_CONFIRMATION_FEATURES = {
|
private final String[] MESSAGE_CONFIRMATION_FEATURES = {
|
||||||
"urn:xmpp:chat-markers:0",
|
"urn:xmpp:chat-markers:0",
|
||||||
"urn:xmpp:receipts"
|
"urn:xmpp:receipts"
|
||||||
|
@ -45,7 +44,7 @@ public abstract class AbstractGenerator {
|
||||||
protected final String IDENTITY_NAME = "Conversations";
|
protected final String IDENTITY_NAME = "Conversations";
|
||||||
protected final String IDENTITY_TYPE = "phone";
|
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;
|
protected XmppConnectionService mXmppConnectionService;
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
package eu.siacs.conversations.parser;
|
package eu.siacs.conversations.parser;
|
||||||
|
|
||||||
|
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import eu.siacs.conversations.entities.Account;
|
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.xml.Element;
|
||||||
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
|
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
|
||||||
import eu.siacs.conversations.xmpp.jid.Jid;
|
import eu.siacs.conversations.xmpp.jid.Jid;
|
||||||
import eu.siacs.conversations.xmpp.stanzas.AbstractStanza;
|
|
||||||
|
|
||||||
public abstract class AbstractParser {
|
public abstract class AbstractParser {
|
||||||
|
|
||||||
|
@ -24,42 +21,48 @@ public abstract class AbstractParser {
|
||||||
this.mXmppConnectionService = service;
|
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");
|
Element delay = element.findChild("delay","urn:xmpp:delay");
|
||||||
if (delay != null) {
|
if (delay != null) {
|
||||||
String stamp = delay.getAttribute("stamp");
|
String stamp = delay.getAttribute("stamp");
|
||||||
if (stamp != null) {
|
if (stamp != null) {
|
||||||
try {
|
try {
|
||||||
return AbstractParser.parseTimestamp(delay.getAttribute("stamp")).getTime();
|
return AbstractParser.parseTimestamp(delay.getAttribute("stamp"));
|
||||||
} catch (ParseException e) {
|
} catch (ParseException e) {
|
||||||
return defaultValue;
|
return d;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return defaultValue;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected long getTimestamp(Element packet) {
|
public static long parseTimestamp(Element element) {
|
||||||
return getTimestamp(packet,System.currentTimeMillis());
|
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");
|
timestamp = timestamp.replace("Z", "+0000");
|
||||||
SimpleDateFormat dateFormat;
|
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());
|
timestamp = timestamp.substring(0,19)+timestamp.substring(timestamp.length() -5,timestamp.length());
|
||||||
dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ",Locale.US);
|
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(long timestamp, final Account account, final Jid from) {
|
protected void updateLastseen(final Account account, final Jid from) {
|
||||||
final String presence = from == null || from.isBareJid() ? "" : from.getResourcepart();
|
|
||||||
final Contact contact = account.getRoster().getContact(from);
|
final Contact contact = account.getRoster().getContact(from);
|
||||||
if (timestamp >= contact.lastseen.time) {
|
contact.setLastPresence(from.isBareJid() ? "" : from.getResourcepart());
|
||||||
contact.lastseen.time = timestamp;
|
|
||||||
if (!presence.isEmpty()) {
|
|
||||||
contact.lastseen.presence = presence;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String avatarData(Element items) {
|
protected String avatarData(Element items) {
|
||||||
|
|
|
@ -7,12 +7,12 @@ import android.util.Pair;
|
||||||
import net.java.otr4j.session.Session;
|
import net.java.otr4j.session.Session;
|
||||||
import net.java.otr4j.session.SessionStatus;
|
import net.java.otr4j.session.SessionStatus;
|
||||||
|
|
||||||
|
import java.text.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ import eu.siacs.conversations.http.HttpConnectionManager;
|
||||||
import eu.siacs.conversations.services.MessageArchiveService;
|
import eu.siacs.conversations.services.MessageArchiveService;
|
||||||
import eu.siacs.conversations.services.XmppConnectionService;
|
import eu.siacs.conversations.services.XmppConnectionService;
|
||||||
import eu.siacs.conversations.utils.CryptoHelper;
|
import eu.siacs.conversations.utils.CryptoHelper;
|
||||||
|
import eu.siacs.conversations.utils.Xmlns;
|
||||||
import eu.siacs.conversations.xml.Element;
|
import eu.siacs.conversations.xml.Element;
|
||||||
import eu.siacs.conversations.xmpp.OnMessagePacketReceived;
|
import eu.siacs.conversations.xmpp.OnMessagePacketReceived;
|
||||||
import eu.siacs.conversations.xmpp.chatstate.ChatState;
|
import eu.siacs.conversations.xmpp.chatstate.ChatState;
|
||||||
|
@ -328,7 +329,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timestamp == null) {
|
if (timestamp == null) {
|
||||||
timestamp = AbstractParser.getTimestamp(packet, System.currentTimeMillis());
|
timestamp = AbstractParser.parseTimestamp(packet);
|
||||||
}
|
}
|
||||||
final String body = packet.getBody();
|
final String body = packet.getBody();
|
||||||
final Element mucUserElement = packet.findChild("x", "http://jabber.org/protocol/muc#user");
|
final Element mucUserElement = packet.findChild("x", "http://jabber.org/protocol/muc#user");
|
||||||
|
@ -439,7 +440,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
|
||||||
message.setType(Message.TYPE_PRIVATE);
|
message.setType(Message.TYPE_PRIVATE);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
updateLastseen(timestamp, account, from);
|
updateLastseen(account, from);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (replacementId != null && mXmppConnectionService.allowMessageCorrection()) {
|
if (replacementId != null && mXmppConnectionService.allowMessageCorrection()) {
|
||||||
|
@ -601,7 +602,6 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
|
||||||
mXmppConnectionService.markRead(conversation);
|
mXmppConnectionService.markRead(conversation);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
updateLastseen(timestamp, account, from);
|
|
||||||
final Message displayedMessage = mXmppConnectionService.markMessage(account, from.toBareJid(), displayed.getAttribute("id"), Message.STATUS_SEND_DISPLAYED);
|
final Message displayedMessage = mXmppConnectionService.markMessage(account, from.toBareJid(), displayed.getAttribute("id"), Message.STATUS_SEND_DISPLAYED);
|
||||||
Message message = displayedMessage == null ? null : displayedMessage.prev();
|
Message message = displayedMessage == null ? null : displayedMessage.prev();
|
||||||
while (message != null
|
while (message != null
|
||||||
|
|
|
@ -2,6 +2,7 @@ package eu.siacs.conversations.parser;
|
||||||
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.text.ParseException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -206,6 +207,20 @@ public class PresenceParser extends AbstractParser implements
|
||||||
mXmppConnectionService.fetchCaps(account, from, presence);
|
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();
|
PgpEngine pgp = mXmppConnectionService.getPgpEngine();
|
||||||
Element x = packet.findChild("x", "jabber:x:signed");
|
Element x = packet.findChild("x", "jabber:x:signed");
|
||||||
if (pgp != null && x != null) {
|
if (pgp != null && x != null) {
|
||||||
|
|
|
@ -20,7 +20,6 @@ import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.FileObserver;
|
import android.os.FileObserver;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.Looper;
|
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
import android.os.PowerManager.WakeLock;
|
import android.os.PowerManager.WakeLock;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
|
@ -80,6 +79,7 @@ import eu.siacs.conversations.entities.Roster;
|
||||||
import eu.siacs.conversations.entities.ServiceDiscoveryResult;
|
import eu.siacs.conversations.entities.ServiceDiscoveryResult;
|
||||||
import eu.siacs.conversations.entities.Transferable;
|
import eu.siacs.conversations.entities.Transferable;
|
||||||
import eu.siacs.conversations.entities.TransferablePlaceholder;
|
import eu.siacs.conversations.entities.TransferablePlaceholder;
|
||||||
|
import eu.siacs.conversations.generator.AbstractGenerator;
|
||||||
import eu.siacs.conversations.generator.IqGenerator;
|
import eu.siacs.conversations.generator.IqGenerator;
|
||||||
import eu.siacs.conversations.generator.MessageGenerator;
|
import eu.siacs.conversations.generator.MessageGenerator;
|
||||||
import eu.siacs.conversations.generator.PresenceGenerator;
|
import eu.siacs.conversations.generator.PresenceGenerator;
|
||||||
|
@ -141,6 +141,9 @@ public class XmppConnectionService extends Service {
|
||||||
private final List<Conversation> conversations = new CopyOnWriteArrayList<>();
|
private final List<Conversation> conversations = new CopyOnWriteArrayList<>();
|
||||||
private final IqGenerator mIqGenerator = new IqGenerator(this);
|
private final IqGenerator mIqGenerator = new IqGenerator(this);
|
||||||
private final List<String> mInProgressAvatarFetches = new ArrayList<>();
|
private final List<String> mInProgressAvatarFetches = new ArrayList<>();
|
||||||
|
|
||||||
|
private long mLastActivity = 0;
|
||||||
|
|
||||||
public DatabaseBackend databaseBackend;
|
public DatabaseBackend databaseBackend;
|
||||||
private ContentObserver contactObserver = new ContentObserver(null) {
|
private ContentObserver contactObserver = new ContentObserver(null) {
|
||||||
@Override
|
@Override
|
||||||
|
@ -1584,6 +1587,7 @@ public class XmppConnectionService extends Service {
|
||||||
|
|
||||||
public void setOnConversationListChangedListener(OnConversationUpdate listener) {
|
public void setOnConversationListChangedListener(OnConversationUpdate listener) {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
|
this.mLastActivity = System.currentTimeMillis();
|
||||||
if (checkListeners()) {
|
if (checkListeners()) {
|
||||||
switchToForeground();
|
switchToForeground();
|
||||||
}
|
}
|
||||||
|
@ -1796,15 +1800,21 @@ public class XmppConnectionService extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void switchToForeground() {
|
private void switchToForeground() {
|
||||||
|
final boolean broadcastLastActivity = broadcastLastActivity();
|
||||||
for (Conversation conversation : getConversations()) {
|
for (Conversation conversation : getConversations()) {
|
||||||
conversation.setIncomingChatState(ChatState.ACTIVE);
|
conversation.setIncomingChatState(ChatState.ACTIVE);
|
||||||
}
|
}
|
||||||
for (Account account : getAccounts()) {
|
for (Account account : getAccounts()) {
|
||||||
if (account.getStatus() == Account.State.ONLINE) {
|
if (account.getStatus() == Account.State.ONLINE) {
|
||||||
account.deactivateGracePeriod();
|
account.deactivateGracePeriod();
|
||||||
XmppConnection connection = account.getXmppConnection();
|
final XmppConnection connection = account.getXmppConnection();
|
||||||
if (connection != null && connection.getFeatures().csi()) {
|
if (connection != null ) {
|
||||||
connection.sendActive();
|
if (connection.getFeatures().csi()) {
|
||||||
|
connection.sendActive();
|
||||||
|
}
|
||||||
|
if (broadcastLastActivity) {
|
||||||
|
sendPresence(account, false); //send new presence but don't include idle because we are not
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1812,6 +1822,7 @@ public class XmppConnectionService extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void switchToBackground() {
|
private void switchToBackground() {
|
||||||
|
final boolean broadcastLastActivity = broadcastLastActivity();
|
||||||
for (Account account : getAccounts()) {
|
for (Account account : getAccounts()) {
|
||||||
if (account.getStatus() == Account.State.ONLINE) {
|
if (account.getStatus() == Account.State.ONLINE) {
|
||||||
XmppConnection connection = account.getXmppConnection();
|
XmppConnection connection = account.getXmppConnection();
|
||||||
|
@ -1819,6 +1830,9 @@ public class XmppConnectionService extends Service {
|
||||||
if (connection.getFeatures().csi()) {
|
if (connection.getFeatures().csi()) {
|
||||||
connection.sendInactive();
|
connection.sendInactive();
|
||||||
}
|
}
|
||||||
|
if (broadcastLastActivity) {
|
||||||
|
sendPresence(account, broadcastLastActivity);
|
||||||
|
}
|
||||||
if (Config.CLOSE_TCP_WHEN_SWITCHING_TO_BACKGROUND && mPushManagementService.available(account)) {
|
if (Config.CLOSE_TCP_WHEN_SWITCHING_TO_BACKGROUND && mPushManagementService.available(account)) {
|
||||||
connection.waitForPush();
|
connection.waitForPush();
|
||||||
cancelWakeUpCall(account.getUuid().hashCode());
|
cancelWakeUpCall(account.getUuid().hashCode());
|
||||||
|
@ -2253,6 +2267,7 @@ public class XmppConnectionService extends Service {
|
||||||
private void disconnect(Account account, boolean force) {
|
private void disconnect(Account account, boolean force) {
|
||||||
if ((account.getStatus() == Account.State.ONLINE)
|
if ((account.getStatus() == Account.State.ONLINE)
|
||||||
|| (account.getStatus() == Account.State.DISABLED)) {
|
|| (account.getStatus() == Account.State.DISABLED)) {
|
||||||
|
final XmppConnection connection = account.getXmppConnection();
|
||||||
if (!force) {
|
if (!force) {
|
||||||
List<Conversation> conversations = getConversations();
|
List<Conversation> conversations = getConversations();
|
||||||
for (Conversation conversation : conversations) {
|
for (Conversation conversation : conversations) {
|
||||||
|
@ -2270,7 +2285,7 @@ public class XmppConnectionService extends Service {
|
||||||
}
|
}
|
||||||
sendOfflinePresence(account);
|
sendOfflinePresence(account);
|
||||||
}
|
}
|
||||||
account.getXmppConnection().disconnect(force);
|
connection.disconnect(force);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2814,6 +2829,10 @@ public class XmppConnectionService extends Service {
|
||||||
return getPreferences().getBoolean("show_connection_options", false);
|
return getPreferences().getBoolean("show_connection_options", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean broadcastLastActivity() {
|
||||||
|
return getPreferences().getBoolean("last_activity", false);
|
||||||
|
}
|
||||||
|
|
||||||
public int unreadCount() {
|
public int unreadCount() {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (Conversation conversation : getConversations()) {
|
for (Conversation conversation : getConversations()) {
|
||||||
|
@ -3052,6 +3071,10 @@ public class XmppConnectionService extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendPresence(final Account account) {
|
public void sendPresence(final Account account) {
|
||||||
|
sendPresence(account, checkListeners() && broadcastLastActivity());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendPresence(final Account account, final boolean includeIdleTimestamp) {
|
||||||
PresencePacket packet;
|
PresencePacket packet;
|
||||||
if (manuallyChangePresence()) {
|
if (manuallyChangePresence()) {
|
||||||
packet = mPresenceGenerator.selfPresence(account, account.getPresenceStatus());
|
packet = mPresenceGenerator.selfPresence(account, account.getPresenceStatus());
|
||||||
|
@ -3062,6 +3085,10 @@ public class XmppConnectionService extends Service {
|
||||||
} else {
|
} else {
|
||||||
packet = mPresenceGenerator.selfPresence(account, getTargetPresence());
|
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);
|
sendPresencePacket(account, packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3072,9 +3099,10 @@ public class XmppConnectionService extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void refreshAllPresences() {
|
public void refreshAllPresences() {
|
||||||
|
boolean includeIdleTimestamp = checkListeners() && broadcastLastActivity();
|
||||||
for (Account account : getAccounts()) {
|
for (Account account : getAccounts()) {
|
||||||
if (!account.isOptionSet(Account.OPTION_DISABLED)) {
|
if (!account.isOptionSet(Account.OPTION_DISABLED)) {
|
||||||
sendPresence(account);
|
sendPresence(account, includeIdleTimestamp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,6 +104,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
private Jid accountJid;
|
private Jid accountJid;
|
||||||
|
private TextView lastseen;
|
||||||
private Jid contactJid;
|
private Jid contactJid;
|
||||||
private TextView contactJidTv;
|
private TextView contactJidTv;
|
||||||
private TextView accountJidTv;
|
private TextView accountJidTv;
|
||||||
|
@ -114,7 +115,8 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
|
||||||
private QuickContactBadge badge;
|
private QuickContactBadge badge;
|
||||||
private LinearLayout keys;
|
private LinearLayout keys;
|
||||||
private LinearLayout tags;
|
private LinearLayout tags;
|
||||||
private boolean showDynamicTags;
|
private boolean showDynamicTags = false;
|
||||||
|
private boolean showLastSeen = false;
|
||||||
private String messageFingerprint;
|
private String messageFingerprint;
|
||||||
|
|
||||||
private DialogInterface.OnClickListener addToPhonebook = new DialogInterface.OnClickListener() {
|
private DialogInterface.OnClickListener addToPhonebook = new DialogInterface.OnClickListener() {
|
||||||
|
@ -203,6 +205,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
|
||||||
|
|
||||||
contactJidTv = (TextView) findViewById(R.id.details_contactjid);
|
contactJidTv = (TextView) findViewById(R.id.details_contactjid);
|
||||||
accountJidTv = (TextView) findViewById(R.id.details_account);
|
accountJidTv = (TextView) findViewById(R.id.details_account);
|
||||||
|
lastseen = (TextView) findViewById(R.id.details_lastseen);
|
||||||
statusMessage = (TextView) findViewById(R.id.status_message);
|
statusMessage = (TextView) findViewById(R.id.status_message);
|
||||||
send = (CheckBox) findViewById(R.id.details_send_presence);
|
send = (CheckBox) findViewById(R.id.details_send_presence);
|
||||||
receive = (CheckBox) findViewById(R.id.details_receive_presence);
|
receive = (CheckBox) findViewById(R.id.details_receive_presence);
|
||||||
|
@ -220,9 +223,14 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
|
||||||
getActionBar().setHomeButtonEnabled(true);
|
getActionBar().setHomeButtonEnabled(true);
|
||||||
getActionBar().setDisplayHomeAsUpEnabled(true);
|
getActionBar().setDisplayHomeAsUpEnabled(true);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStart() {
|
||||||
|
super.onStart();
|
||||||
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
|
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
this.showDynamicTags = preferences.getBoolean("show_dynamic_tags",false);
|
this.showDynamicTags = preferences.getBoolean("show_dynamic_tags",false);
|
||||||
|
this.showLastSeen = preferences.getBoolean("last_activity", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -371,6 +379,18 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
|
||||||
statusMessage.setVisibility(View.GONE);
|
statusMessage.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
if (contact.getPresences().size() > 1) {
|
||||||
contactJidTv.setText(contact.getDisplayJid() + " ("
|
contactJidTv.setText(contact.getDisplayJid() + " ("
|
||||||
+ contact.getPresences().size() + ")");
|
+ contact.getPresences().size() + ")");
|
||||||
|
|
|
@ -162,7 +162,8 @@ public class SettingsActivity extends XmppActivity implements
|
||||||
"away_when_screen_off",
|
"away_when_screen_off",
|
||||||
"allow_message_correction",
|
"allow_message_correction",
|
||||||
"treat_vibrate_as_silent",
|
"treat_vibrate_as_silent",
|
||||||
"manually_change_presence");
|
"manually_change_presence",
|
||||||
|
"last_activity");
|
||||||
if (name.equals("resource")) {
|
if (name.equals("resource")) {
|
||||||
String resource = preferences.getString("resource", "mobile")
|
String resource = preferences.getString("resource", "mobile")
|
||||||
.toLowerCase(Locale.US);
|
.toLowerCase(Locale.US);
|
||||||
|
|
|
@ -912,7 +912,7 @@ public abstract class XmppActivity extends Activity {
|
||||||
final String[] presencesArray = presences.asStringArray();
|
final String[] presencesArray = presences.asStringArray();
|
||||||
int preselectedPresence = 0;
|
int preselectedPresence = 0;
|
||||||
for (int i = 0; i < presencesArray.length; ++i) {
|
for (int i = 0; i < presencesArray.length; ++i) {
|
||||||
if (presencesArray[i].equals(contact.lastseen.presence)) {
|
if (presencesArray[i].equals(contact.getLastPresence())) {
|
||||||
preselectedPresence = i;
|
preselectedPresence = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,12 +107,10 @@ public class UIHelper {
|
||||||
.get(Calendar.DAY_OF_YEAR);
|
.get(Calendar.DAY_OF_YEAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String lastseen(Context context, long time) {
|
public static String lastseen(Context context, boolean active, long time) {
|
||||||
if (time == 0) {
|
|
||||||
return context.getString(R.string.never_seen);
|
|
||||||
}
|
|
||||||
long difference = (System.currentTimeMillis() - time) / 1000;
|
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);
|
return context.getString(R.string.last_seen_now);
|
||||||
} else if (difference < 60 * 2) {
|
} else if (difference < 60 * 2) {
|
||||||
return context.getString(R.string.last_seen_min);
|
return context.getString(R.string.last_seen_min);
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
package eu.siacs.conversations.utils;
|
package eu.siacs.conversations.utils;
|
||||||
|
|
||||||
import eu.siacs.conversations.Config;
|
|
||||||
|
|
||||||
public final class Xmlns {
|
public final class Xmlns {
|
||||||
public static final String BLOCKING = "urn:xmpp:blocking";
|
public static final String BLOCKING = "urn:xmpp:blocking";
|
||||||
public static final String ROSTER = "jabber:iq:roster";
|
public static final String ROSTER = "jabber:iq:roster";
|
||||||
|
|
|
@ -83,7 +83,7 @@ public class MessagePacket extends AbstractAcknowledgeableStanza {
|
||||||
if (packet == null) {
|
if (packet == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Long timestamp = AbstractParser.getTimestamp(forwarded,null);
|
Long timestamp = AbstractParser.parseTimestamp(forwarded, null);
|
||||||
return new Pair(packet,timestamp);
|
return new Pair(packet,timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,12 +53,20 @@
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal">
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/details_lastseen"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/black54"
|
||||||
|
android:textSize="?attr/TextSizeBody" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:id="@+id/status_message"
|
android:id="@+id/status_message"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textColor="@color/black54"
|
android:textColor="@color/black87"
|
||||||
android:textStyle="italic"
|
android:textStyle="italic"
|
||||||
android:textSize="?attr/TextSizeBody" />
|
android:textSize="?attr/TextSizeBody" />
|
||||||
|
|
||||||
|
|
|
@ -653,4 +653,7 @@
|
||||||
<string name="gp_short">Short</string>
|
<string name="gp_short">Short</string>
|
||||||
<string name="gp_medium">Medium</string>
|
<string name="gp_medium">Medium</string>
|
||||||
<string name="gp_long">Long</string>
|
<string name="gp_long">Long</string>
|
||||||
|
<string name="pref_broadcast_last_activity">Broadcast last activity</string>
|
||||||
|
<string name="pref_broadcast_last_activity_summary">Let all your contacts know when use Conversations</string>
|
||||||
|
<string name="pref_privacy">Privacy</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
android:key="resource"
|
android:key="resource"
|
||||||
android:summary="@string/pref_xmpp_resource_summary"
|
android:summary="@string/pref_xmpp_resource_summary"
|
||||||
android:title="@string/pref_xmpp_resource"/>
|
android:title="@string/pref_xmpp_resource"/>
|
||||||
|
</PreferenceCategory>
|
||||||
|
<PreferenceCategory android:title="@string/pref_privacy">
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
android:defaultValue="true"
|
android:defaultValue="true"
|
||||||
android:key="confirm_messages"
|
android:key="confirm_messages"
|
||||||
|
@ -26,11 +28,13 @@
|
||||||
android:key="chat_states"
|
android:key="chat_states"
|
||||||
android:summary="@string/pref_chat_states_summary"
|
android:summary="@string/pref_chat_states_summary"
|
||||||
android:title="@string/pref_chat_states"/>
|
android:title="@string/pref_chat_states"/>
|
||||||
|
<CheckBoxPreference
|
||||||
</PreferenceCategory>
|
android:defaultValue="false"
|
||||||
<PreferenceCategory
|
android:key="last_activity"
|
||||||
android:key="notifications"
|
android:title="@string/pref_broadcast_last_activity"
|
||||||
android:title="@string/pref_notification_settings">
|
android:summary="@string/pref_broadcast_last_activity_summary"/>
|
||||||
|
</PreferenceCategory>
|
||||||
|
<PreferenceCategory android:title="@string/pref_notification_settings">
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
android:defaultValue="true"
|
android:defaultValue="true"
|
||||||
android:key="show_notification"
|
android:key="show_notification"
|
||||||
|
@ -88,8 +92,7 @@
|
||||||
android:entryValues="@array/grace_periods_values"
|
android:entryValues="@array/grace_periods_values"
|
||||||
/>
|
/>
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
<PreferenceCategory
|
<PreferenceCategory android:title="@string/pref_attachments">
|
||||||
android:title="@string/pref_attachments">
|
|
||||||
<ListPreference
|
<ListPreference
|
||||||
android:defaultValue="524288"
|
android:defaultValue="524288"
|
||||||
android:entries="@array/filesizes"
|
android:entries="@array/filesizes"
|
||||||
|
|
Loading…
Reference in a new issue