aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Gultsch <daniel@gultsch.de>2016-06-04 16:16:14 +0200
committerDaniel Gultsch <daniel@gultsch.de>2016-06-04 16:16:14 +0200
commit71e911717697078141c3669134ad9268e9753ea0 (patch)
tree93c9833d28048c15aefe4109105523a4a0e002d9
parent6639d0f23bb983cae7234d6b15f9875464c67093 (diff)
opt-in to send last userinteraction in presence
-rw-r--r--docs/XEPs.md1
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Contact.java55
-rw-r--r--src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java7
-rw-r--r--src/main/java/eu/siacs/conversations/parser/AbstractParser.java41
-rw-r--r--src/main/java/eu/siacs/conversations/parser/MessageParser.java8
-rw-r--r--src/main/java/eu/siacs/conversations/parser/PresenceParser.java15
-rw-r--r--src/main/java/eu/siacs/conversations/services/XmppConnectionService.java40
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java22
-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/utils/Xmlns.java2
-rw-r--r--src/main/java/eu/siacs/conversations/xmpp/stanzas/MessagePacket.java2
-rw-r--r--src/main/res/layout/activity_contact_details.xml10
-rw-r--r--src/main/res/values/strings.xml3
-rw-r--r--src/main/res/xml/preferences.xml17
16 files changed, 165 insertions, 71 deletions
diff --git a/docs/XEPs.md b/docs/XEPs.md
index 873ea998..48ce4815 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/src/main/java/eu/siacs/conversations/entities/Contact.java b/src/main/java/eu/siacs/conversations/entities/Contact.java
index 8721d9c4..70878a73 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 9e839683..ff9a20c6 100644
--- a/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java
+++ b/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java
@@ -16,8 +16,6 @@ import eu.siacs.conversations.Config;
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.utils.PhoneHelper;
-import eu.siacs.conversations.xmpp.jid.Jid;
-import eu.siacs.conversations.xmpp.stanzas.IqPacket;
public abstract class AbstractGenerator {
private final String[] FEATURES = {
@@ -33,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 +44,7 @@ public abstract class AbstractGenerator {
protected final String IDENTITY_NAME = "Conversations";
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 03f19ed8..4699d286 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,42 +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(long timestamp, final Account account, final Jid from) {
- final String presence = from == null || from.isBareJid() ? "" : from.getResourcepart();
+ protected void updateLastseen(final Account account, final Jid from) {
final Contact contact = account.getRoster().getContact(from);
- if (timestamp >= contact.lastseen.time) {
- contact.lastseen.time = timestamp;
- if (!presence.isEmpty()) {
- contact.lastseen.presence = presence;
- }
- }
+ contact.setLastPresence(from.isBareJid() ? "" : from.getResourcepart());
}
protected String avatarData(Element items) {
diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java
index 48862c47..2bdb747d 100644
--- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java
+++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java
@@ -7,12 +7,12 @@ 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;
import java.util.Date;
import java.util.List;
-import java.util.Locale;
import java.util.Set;
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.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;
@@ -328,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");
@@ -439,7 +440,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
message.setType(Message.TYPE_PRIVATE);
}
} else {
- updateLastseen(timestamp, account, from);
+ updateLastseen(account, from);
}
if (replacementId != null && mXmppConnectionService.allowMessageCorrection()) {
@@ -601,7 +602,6 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
mXmppConnectionService.markRead(conversation);
}
} else {
- updateLastseen(timestamp, account, from);
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 b5718b61..b11a6eff 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;
@@ -206,6 +207,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) {
diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
index fc8159af..fa07019f 100644
--- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
+++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
@@ -20,7 +20,6 @@ import android.os.Build;
import android.os.Bundle;
import android.os.FileObserver;
import android.os.IBinder;
-import android.os.Looper;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
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.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;
@@ -141,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
@@ -1584,6 +1587,7 @@ public class XmppConnectionService extends Service {
public void setOnConversationListChangedListener(OnConversationUpdate listener) {
synchronized (this) {
+ this.mLastActivity = System.currentTimeMillis();
if (checkListeners()) {
switchToForeground();
}
@@ -1796,15 +1800,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
+ }
}
}
}
@@ -1812,6 +1822,7 @@ 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();
@@ -1819,6 +1830,9 @@ public class XmppConnectionService extends Service {
if (connection.getFeatures().csi()) {
connection.sendInactive();
}
+ if (broadcastLastActivity) {
+ sendPresence(account, broadcastLastActivity);
+ }
if (Config.CLOSE_TCP_WHEN_SWITCHING_TO_BACKGROUND && mPushManagementService.available(account)) {
connection.waitForPush();
cancelWakeUpCall(account.getUuid().hashCode());
@@ -2253,6 +2267,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) {
@@ -2270,7 +2285,7 @@ public class XmppConnectionService extends Service {
}
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);
}
+ public boolean broadcastLastActivity() {
+ return getPreferences().getBoolean("last_activity", false);
+ }
+
public int unreadCount() {
int count = 0;
for (Conversation conversation : getConversations()) {
@@ -3052,6 +3071,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());
@@ -3062,6 +3085,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);
}
@@ -3072,9 +3099,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 de0979a6..b67aae18 100644
--- a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java
@@ -104,6 +104,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
}
};
private Jid accountJid;
+ private TextView lastseen;
private Jid contactJid;
private TextView contactJidTv;
private TextView accountJidTv;
@@ -114,7 +115,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() {
@@ -203,6 +205,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);
statusMessage = (TextView) findViewById(R.id.status_message);
send = (CheckBox) findViewById(R.id.details_send_presence);
receive = (CheckBox) findViewById(R.id.details_receive_presence);
@@ -220,9 +223,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", false);
}
@Override
@@ -371,6 +379,18 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
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) {
contactJidTv.setText(contact.getDisplayJid() + " ("
+ contact.getPresences().size() + ")");
diff --git a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java
index cd843b25..22e12633 100644
--- a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java
@@ -162,7 +162,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 5dfa5083..c6301643 100644
--- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
@@ -912,7 +912,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 4ab74818..acc7f28c 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/utils/Xmlns.java b/src/main/java/eu/siacs/conversations/utils/Xmlns.java
index ad30b3e6..de0a29ce 100644
--- a/src/main/java/eu/siacs/conversations/utils/Xmlns.java
+++ b/src/main/java/eu/siacs/conversations/utils/Xmlns.java
@@ -1,7 +1,5 @@
package eu.siacs.conversations.utils;
-import eu.siacs.conversations.Config;
-
public final class Xmlns {
public static final String BLOCKING = "urn:xmpp:blocking";
public static final String ROSTER = "jabber:iq:roster";
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 941b4b5f..ac75a5e5 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/layout/activity_contact_details.xml b/src/main/res/layout/activity_contact_details.xml
index 0facc651..3c9d203b 100644
--- a/src/main/res/layout/activity_contact_details.xml
+++ b/src/main/res/layout/activity_contact_details.xml
@@ -54,11 +54,19 @@
</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
android:layout_marginTop="8dp"
android:id="@+id/status_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textColor="@color/black54"
+ android:textColor="@color/black87"
android:textStyle="italic"
android:textSize="?attr/TextSizeBody" />
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index 757ebb0a..7f4ac005 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -653,4 +653,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 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>
diff --git a/src/main/res/xml/preferences.xml b/src/main/res/xml/preferences.xml
index fb0103ed..eb1ff571 100644
--- a/src/main/res/xml/preferences.xml
+++ b/src/main/res/xml/preferences.xml
@@ -15,6 +15,8 @@
android:key="resource"
android:summary="@string/pref_xmpp_resource_summary"
android:title="@string/pref_xmpp_resource"/>
+ </PreferenceCategory>
+ <PreferenceCategory android:title="@string/pref_privacy">
<CheckBoxPreference
android:defaultValue="true"
android:key="confirm_messages"
@@ -26,11 +28,13 @@
android:key="chat_states"
android:summary="@string/pref_chat_states_summary"
android:title="@string/pref_chat_states"/>
-
- </PreferenceCategory>
- <PreferenceCategory
- android:key="notifications"
- android:title="@string/pref_notification_settings">
+ <CheckBoxPreference
+ android:defaultValue="false"
+ android:key="last_activity"
+ android:title="@string/pref_broadcast_last_activity"
+ android:summary="@string/pref_broadcast_last_activity_summary"/>
+ </PreferenceCategory>
+ <PreferenceCategory android:title="@string/pref_notification_settings">
<CheckBoxPreference
android:defaultValue="true"
android:key="show_notification"
@@ -88,8 +92,7 @@
android:entryValues="@array/grace_periods_values"
/>
</PreferenceCategory>
- <PreferenceCategory
- android:title="@string/pref_attachments">
+ <PreferenceCategory android:title="@string/pref_attachments">
<ListPreference
android:defaultValue="524288"
android:entries="@array/filesizes"