From 0e96e0a796661aae1af133f24d010a4957f68af2 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Thu, 28 Jul 2016 22:58:37 +0200 Subject: show identity type for device selection --- .../eu/siacs/conversations/entities/Contact.java | 6 +- .../eu/siacs/conversations/entities/Message.java | 6 +- .../eu/siacs/conversations/entities/Presences.java | 29 +++++- .../siacs/conversations/parser/AbstractParser.java | 2 +- .../conversations/persistance/FileBackend.java | 7 +- .../services/XmppConnectionService.java | 2 +- .../eu/siacs/conversations/ui/XmppActivity.java | 101 ++++++++++++++------- .../eu/siacs/conversations/utils/CryptoHelper.java | 3 + .../eu/siacs/conversations/utils/UIHelper.java | 18 ++++ src/main/res/values/strings.xml | 7 +- 10 files changed, 135 insertions(+), 46 deletions(-) (limited to 'src/main') diff --git a/src/main/java/eu/siacs/conversations/entities/Contact.java b/src/main/java/eu/siacs/conversations/entities/Contact.java index f061413b..676c91d0 100644 --- a/src/main/java/eu/siacs/conversations/entities/Contact.java +++ b/src/main/java/eu/siacs/conversations/entities/Contact.java @@ -526,11 +526,11 @@ public class Contact implements ListItem, Blockable { return this.mLastseen; } - public void setLastPresence(String presence) { - this.mLastPresence = presence; + public void setLastResource(String resource) { + this.mLastPresence = resource; } - public String getLastPresence() { + public String getLastResource() { return this.mLastPresence; } diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index 9ab1da96..1b38d349 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -5,10 +5,10 @@ import android.database.Cursor; import java.net.MalformedURLException; import java.net.URL; -import java.util.Arrays; import eu.siacs.conversations.Config; import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession; +import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.utils.GeoHelper; import eu.siacs.conversations.utils.MimeUtils; import eu.siacs.conversations.utils.UIHelper; @@ -396,7 +396,7 @@ public class Message extends AbstractEntity { && this.counterpart.equals(message.getCounterpart()) && (body.equals(otherBody) ||(message.getEncryption() == Message.ENCRYPTION_PGP - && message.getRemoteMsgId().matches("[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}"))) ; + && CryptoHelper.UUID_PATTERN.matcher(message.getRemoteMsgId()).matches())); } else { return this.remoteMsgId == null && this.counterpart.equals(message.getCounterpart()) @@ -550,7 +550,7 @@ public class Message extends AbstractEntity { try { counterpart = Jid.fromParts(conversation.getJid().getLocalpart(), conversation.getJid().getDomainpart(), - presences.asStringArray()[0]); + presences.toResourceArray()[0]); return true; } catch (InvalidJidException e) { counterpart = null; diff --git a/src/main/java/eu/siacs/conversations/entities/Presences.java b/src/main/java/eu/siacs/conversations/entities/Presences.java index 6391f5bb..f9dfee36 100644 --- a/src/main/java/eu/siacs/conversations/entities/Presences.java +++ b/src/main/java/eu/siacs/conversations/entities/Presences.java @@ -1,7 +1,10 @@ package eu.siacs.conversations.entities; +import android.util.Pair; + import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.Hashtable; import java.util.Iterator; import java.util.List; @@ -54,7 +57,7 @@ public class Presences { } } - public String[] asStringArray() { + public String[] toResourceArray() { synchronized (this.presences) { final String[] presencesArray = new String[presences.size()]; presences.keySet().toArray(presencesArray); @@ -104,4 +107,28 @@ public class Presences { } return true; } + + public Pair,Map> toTypeAndNameMap() { + Map typeMap = new HashMap<>(); + Map nameMap = new HashMap<>(); + synchronized (this.presences) { + for(Map.Entry presenceEntry : this.presences.entrySet()) { + String resource = presenceEntry.getKey(); + Presence presence = presenceEntry.getValue(); + ServiceDiscoveryResult serviceDiscoveryResult = presence == null ? null : presence.getServiceDiscoveryResult(); + if (serviceDiscoveryResult != null && serviceDiscoveryResult.getIdentities().size() > 0) { + ServiceDiscoveryResult.Identity identity = serviceDiscoveryResult.getIdentities().get(0); + String type = identity.getType(); + String name = identity.getName(); + if (type != null) { + typeMap.put(resource,type); + } + if (name != null) { + nameMap.put(resource, name); + } + } + } + } + return new Pair(typeMap,nameMap); + } } diff --git a/src/main/java/eu/siacs/conversations/parser/AbstractParser.java b/src/main/java/eu/siacs/conversations/parser/AbstractParser.java index 4699d286..b548b3c8 100644 --- a/src/main/java/eu/siacs/conversations/parser/AbstractParser.java +++ b/src/main/java/eu/siacs/conversations/parser/AbstractParser.java @@ -62,7 +62,7 @@ public abstract class AbstractParser { protected void updateLastseen(final Account account, final Jid from) { final Contact contact = account.getRoster().getContact(from); - contact.setLastPresence(from.isBareJid() ? "" : from.getResourcepart()); + contact.setLastResource(from.isBareJid() ? "" : from.getResourcepart()); } protected String avatarData(Element items) { diff --git a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java index cd46d1b8..947e19a6 100644 --- a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java @@ -401,7 +401,12 @@ public class FileBackend { private Bitmap getFullsizeImagePreview(File file, int size) { BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = calcSampleSize(file, size); - return BitmapFactory.decodeFile(file.getAbsolutePath(), options); + try { + return BitmapFactory.decodeFile(file.getAbsolutePath(), options); + } catch (OutOfMemoryError e) { + options.inSampleSize *= 2; + return BitmapFactory.decodeFile(file.getAbsolutePath(), options); + } } private Bitmap getVideoPreview(File file, int size) { diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 44840ba2..01aa5a60 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -196,7 +196,7 @@ public class XmppConnectionService extends Service { if (contact.getPresences().size() >= 1) { if (conversation.hasValidOtrSession()) { String otrResource = conversation.getOtrSession().getSessionID().getUserID(); - if (!(Arrays.asList(contact.getPresences().asStringArray()).contains(otrResource))) { + if (!(Arrays.asList(contact.getPresences().toResourceArray()).contains(otrResource))) { conversation.endOtrIfNeeded(); } } diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java index df16fd64..e8047ce2 100644 --- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java @@ -44,6 +44,7 @@ import android.preference.PreferenceManager; import android.text.InputType; import android.util.DisplayMetrics; import android.util.Log; +import android.util.Pair; import android.view.MenuItem; import android.view.View; import android.view.inputmethod.InputMethodManager; @@ -66,9 +67,13 @@ import net.java.otr4j.session.SessionID; import java.io.FileNotFoundException; import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; import java.util.Hashtable; import java.util.List; +import java.util.Map; import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.atomic.AtomicInteger; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; @@ -78,13 +83,16 @@ import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.MucOptions; +import eu.siacs.conversations.entities.Presence; import eu.siacs.conversations.entities.Presences; +import eu.siacs.conversations.entities.ServiceDiscoveryResult; import eu.siacs.conversations.services.AvatarService; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.services.XmppConnectionService.XmppConnectionBinder; import eu.siacs.conversations.ui.widget.Switch; import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.utils.ExceptionHelper; +import eu.siacs.conversations.utils.UIHelper; import eu.siacs.conversations.xmpp.OnKeyStatusUpdated; import eu.siacs.conversations.xmpp.OnUpdateBlocklist; import eu.siacs.conversations.xmpp.jid.InvalidJidException; @@ -940,7 +948,7 @@ public abstract class XmppActivity extends Activity { } else if (!contact.showInRoster()) { showAddToRosterDialog(conversation); } else { - Presences presences = contact.getPresences(); + final Presences presences = contact.getPresences(); if (presences.size() == 0) { if (!contact.getOption(Contact.Options.TO) && !contact.getOption(Contact.Options.ASKING) @@ -954,7 +962,7 @@ public abstract class XmppActivity extends Activity { listener.onPresenceSelected(); } } else if (presences.size() == 1) { - String presence = presences.asStringArray()[0]; + String presence = presences.toResourceArray()[0]; try { conversation.setNextCounterpart(Jid.fromParts(contact.getJid().getLocalpart(),contact.getJid().getDomainpart(),presence)); } catch (InvalidJidException e) { @@ -962,49 +970,72 @@ public abstract class XmppActivity extends Activity { } listener.onPresenceSelected(); } else { - final StringBuilder presence = new StringBuilder(); - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(getString(R.string.choose_presence)); - final String[] presencesArray = presences.asStringArray(); - int preselectedPresence = 0; - for (int i = 0; i < presencesArray.length; ++i) { - if (presencesArray[i].equals(contact.getLastPresence())) { - preselectedPresence = i; - break; + showPresenceSelectionDialog(presences,conversation,listener); + } + } + } + + private void showPresenceSelectionDialog(Presences presences, final Conversation conversation, final OnPresenceSelected listener) { + final Contact contact = conversation.getContact(); + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(getString(R.string.choose_presence)); + final String[] resourceArray = presences.toResourceArray(); + Pair, Map> typeAndName = presences.toTypeAndNameMap(); + final Map resourceTypeMap = typeAndName.first; + final Map resourceNameMap = typeAndName.second; + final String[] readableIdentities = new String[resourceArray.length]; + final AtomicInteger selectedResource = new AtomicInteger(0); + for (int i = 0; i < resourceArray.length; ++i) { + String resource = resourceArray[i]; + if (resource.equals(contact.getLastResource())) { + selectedResource.set(i); + } + String type = resourceTypeMap.get(resource); + String name = resourceNameMap.get(resource); + if (type != null) { + if (Collections.frequency(resourceTypeMap.values(),type) == 1) { + readableIdentities[i] = UIHelper.tranlasteType(this,type); + } else if (name != null) { + if (Collections.frequency(resourceNameMap.values(), name) == 1 + || CryptoHelper.UUID_PATTERN.matcher(resource).matches()) { + readableIdentities[i] = UIHelper.tranlasteType(this,type) + " (" + name+")"; + } else { + readableIdentities[i] = UIHelper.tranlasteType(this,type) + " (" + name +" / " + resource+")"; } + } else { + readableIdentities[i] = UIHelper.tranlasteType(this,type) + " (" + resource+")"; } - presence.append(presencesArray[preselectedPresence]); - builder.setSingleChoiceItems(presencesArray, - preselectedPresence, - new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, - int which) { - presence.delete(0, presence.length()); - presence.append(presencesArray[which]); - } - }); - builder.setNegativeButton(R.string.cancel, null); - builder.setPositiveButton(R.string.ok, new OnClickListener() { + } else { + readableIdentities[i] = resource; + } + } + builder.setSingleChoiceItems(readableIdentities, + selectedResource.get(), + new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - try { - conversation.setNextCounterpart(Jid.fromParts(contact.getJid().getLocalpart(),contact.getJid().getDomainpart(),presence.toString())); - } catch (InvalidJidException e) { - conversation.setNextCounterpart(null); - } - listener.onPresenceSelected(); + selectedResource.set(which); } }); - builder.create().show(); + builder.setNegativeButton(R.string.cancel, null); + builder.setPositiveButton(R.string.ok, new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + try { + Jid next = Jid.fromParts(contact.getJid().getLocalpart(),contact.getJid().getDomainpart(),resourceArray[selectedResource.get()]); + conversation.setNextCounterpart(next); + } catch (InvalidJidException e) { + conversation.setNextCounterpart(null); + } + listener.onPresenceSelected(); } - } + }); + builder.create().show(); } - protected void onActivityResult(int requestCode, int resultCode, - final Intent data) { + protected void onActivityResult(int requestCode, int resultCode, final Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_INVITE_TO_CONVERSATION && resultCode == RESULT_OK) { mPendingConferenceInvite = ConferenceInvite.parse(data); diff --git a/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java b/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java index 253584bf..429c349a 100644 --- a/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/CryptoHelper.java @@ -21,6 +21,7 @@ import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; +import java.util.regex.Pattern; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; @@ -31,6 +32,8 @@ import eu.siacs.conversations.xmpp.jid.Jid; public final class CryptoHelper { public static final String FILETRANSFER = "?FILETRANSFERv1:"; private final static char[] hexArray = "0123456789abcdef".toCharArray(); + + public static final Pattern UUID_PATTERN = Pattern.compile("[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}"); final public static byte[] ONE = new byte[] { 0, 0, 0, 1 }; public static String bytesToHex(byte[] bytes) { diff --git a/src/main/java/eu/siacs/conversations/utils/UIHelper.java b/src/main/java/eu/siacs/conversations/utils/UIHelper.java index acc7f28c..63dae04f 100644 --- a/src/main/java/eu/siacs/conversations/utils/UIHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/UIHelper.java @@ -18,6 +18,7 @@ import eu.siacs.conversations.entities.ListItem; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.Presence; import eu.siacs.conversations.entities.Transferable; +import eu.siacs.conversations.ui.XmppActivity; import eu.siacs.conversations.xmpp.jid.Jid; public class UIHelper { @@ -286,4 +287,21 @@ public class UIHelper { return new ListItem.Tag(context.getString(R.string.presence_online), 0xff259b24); } } + + public static String tranlasteType(Context context, String type) { + switch (type.toLowerCase()) { + case "pc": + return context.getString(R.string.type_pc); + case "phone": + return context.getString(R.string.type_phone); + case "tablet": + return context.getString(R.string.type_tablet); + case "web": + return context.getString(R.string.type_web); + case "console": + return context.getString(R.string.type_console); + default: + return type; + } + } } diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 9b404295..96d7d3cc 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -79,7 +79,7 @@ Do you want to delete all messages within this Conversation?\n\nWarning: This will not influence messages stored on other devices or servers. Delete messages End this conversation afterwards - Choose presence to contact + Choose device Send unencrypted message Send message to %s Send OTR encrypted message @@ -669,4 +669,9 @@ Use green background for received messages Unable to connect to OpenKeychain This device is no longer in use + Computer + Mobile phone + Tablet + Web browser + Console -- cgit v1.2.3