show identity type for device selection

This commit is contained in:
Daniel Gultsch 2016-07-28 22:58:37 +02:00
parent c06aceaae9
commit 0e96e0a796
10 changed files with 141 additions and 52 deletions

View file

@ -526,11 +526,11 @@ public class Contact implements ListItem, Blockable {
return this.mLastseen; return this.mLastseen;
} }
public void setLastPresence(String presence) { public void setLastResource(String resource) {
this.mLastPresence = presence; this.mLastPresence = resource;
} }
public String getLastPresence() { public String getLastResource() {
return this.mLastPresence; return this.mLastPresence;
} }

View file

@ -5,10 +5,10 @@ import android.database.Cursor;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.util.Arrays;
import eu.siacs.conversations.Config; import eu.siacs.conversations.Config;
import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession; import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession;
import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.utils.GeoHelper; import eu.siacs.conversations.utils.GeoHelper;
import eu.siacs.conversations.utils.MimeUtils; import eu.siacs.conversations.utils.MimeUtils;
import eu.siacs.conversations.utils.UIHelper; import eu.siacs.conversations.utils.UIHelper;
@ -396,7 +396,7 @@ public class Message extends AbstractEntity {
&& this.counterpart.equals(message.getCounterpart()) && this.counterpart.equals(message.getCounterpart())
&& (body.equals(otherBody) && (body.equals(otherBody)
||(message.getEncryption() == Message.ENCRYPTION_PGP ||(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 { } else {
return this.remoteMsgId == null return this.remoteMsgId == null
&& this.counterpart.equals(message.getCounterpart()) && this.counterpart.equals(message.getCounterpart())
@ -550,7 +550,7 @@ public class Message extends AbstractEntity {
try { try {
counterpart = Jid.fromParts(conversation.getJid().getLocalpart(), counterpart = Jid.fromParts(conversation.getJid().getLocalpart(),
conversation.getJid().getDomainpart(), conversation.getJid().getDomainpart(),
presences.asStringArray()[0]); presences.toResourceArray()[0]);
return true; return true;
} catch (InvalidJidException e) { } catch (InvalidJidException e) {
counterpart = null; counterpart = null;

View file

@ -1,7 +1,10 @@
package eu.siacs.conversations.entities; package eu.siacs.conversations.entities;
import android.util.Pair;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@ -54,7 +57,7 @@ public class Presences {
} }
} }
public String[] asStringArray() { public String[] toResourceArray() {
synchronized (this.presences) { synchronized (this.presences) {
final String[] presencesArray = new String[presences.size()]; final String[] presencesArray = new String[presences.size()];
presences.keySet().toArray(presencesArray); presences.keySet().toArray(presencesArray);
@ -104,4 +107,28 @@ public class Presences {
} }
return true; return true;
} }
public Pair<Map<String, String>,Map<String,String>> toTypeAndNameMap() {
Map<String,String> typeMap = new HashMap<>();
Map<String,String> nameMap = new HashMap<>();
synchronized (this.presences) {
for(Map.Entry<String,Presence> 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);
}
} }

View file

@ -62,7 +62,7 @@ public abstract class AbstractParser {
protected void updateLastseen(final Account account, final Jid from) { protected void updateLastseen(final Account account, final Jid from) {
final Contact contact = account.getRoster().getContact(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) { protected String avatarData(Element items) {

View file

@ -401,7 +401,12 @@ public class FileBackend {
private Bitmap getFullsizeImagePreview(File file, int size) { private Bitmap getFullsizeImagePreview(File file, int size) {
BitmapFactory.Options options = new BitmapFactory.Options(); BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = calcSampleSize(file, size); 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) { private Bitmap getVideoPreview(File file, int size) {

View file

@ -196,7 +196,7 @@ public class XmppConnectionService extends Service {
if (contact.getPresences().size() >= 1) { if (contact.getPresences().size() >= 1) {
if (conversation.hasValidOtrSession()) { if (conversation.hasValidOtrSession()) {
String otrResource = conversation.getOtrSession().getSessionID().getUserID(); String otrResource = conversation.getOtrSession().getSessionID().getUserID();
if (!(Arrays.asList(contact.getPresences().asStringArray()).contains(otrResource))) { if (!(Arrays.asList(contact.getPresences().toResourceArray()).contains(otrResource))) {
conversation.endOtrIfNeeded(); conversation.endOtrIfNeeded();
} }
} }

View file

@ -44,6 +44,7 @@ import android.preference.PreferenceManager;
import android.text.InputType; import android.text.InputType;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import android.util.Log; import android.util.Log;
import android.util.Pair;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
@ -66,9 +67,13 @@ import net.java.otr4j.session.SessionID;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.atomic.AtomicInteger;
import eu.siacs.conversations.Config; import eu.siacs.conversations.Config;
import eu.siacs.conversations.R; 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.Conversation;
import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.MucOptions; import eu.siacs.conversations.entities.MucOptions;
import eu.siacs.conversations.entities.Presence;
import eu.siacs.conversations.entities.Presences; import eu.siacs.conversations.entities.Presences;
import eu.siacs.conversations.entities.ServiceDiscoveryResult;
import eu.siacs.conversations.services.AvatarService; import eu.siacs.conversations.services.AvatarService;
import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.services.XmppConnectionService.XmppConnectionBinder; import eu.siacs.conversations.services.XmppConnectionService.XmppConnectionBinder;
import eu.siacs.conversations.ui.widget.Switch; import eu.siacs.conversations.ui.widget.Switch;
import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.utils.ExceptionHelper; import eu.siacs.conversations.utils.ExceptionHelper;
import eu.siacs.conversations.utils.UIHelper;
import eu.siacs.conversations.xmpp.OnKeyStatusUpdated; import eu.siacs.conversations.xmpp.OnKeyStatusUpdated;
import eu.siacs.conversations.xmpp.OnUpdateBlocklist; import eu.siacs.conversations.xmpp.OnUpdateBlocklist;
import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.InvalidJidException;
@ -940,7 +948,7 @@ public abstract class XmppActivity extends Activity {
} else if (!contact.showInRoster()) { } else if (!contact.showInRoster()) {
showAddToRosterDialog(conversation); showAddToRosterDialog(conversation);
} else { } else {
Presences presences = contact.getPresences(); final Presences presences = contact.getPresences();
if (presences.size() == 0) { if (presences.size() == 0) {
if (!contact.getOption(Contact.Options.TO) if (!contact.getOption(Contact.Options.TO)
&& !contact.getOption(Contact.Options.ASKING) && !contact.getOption(Contact.Options.ASKING)
@ -954,7 +962,7 @@ public abstract class XmppActivity extends Activity {
listener.onPresenceSelected(); listener.onPresenceSelected();
} }
} else if (presences.size() == 1) { } else if (presences.size() == 1) {
String presence = presences.asStringArray()[0]; String presence = presences.toResourceArray()[0];
try { try {
conversation.setNextCounterpart(Jid.fromParts(contact.getJid().getLocalpart(),contact.getJid().getDomainpart(),presence)); conversation.setNextCounterpart(Jid.fromParts(contact.getJid().getLocalpart(),contact.getJid().getDomainpart(),presence));
} catch (InvalidJidException e) { } catch (InvalidJidException e) {
@ -962,49 +970,72 @@ public abstract class XmppActivity extends Activity {
} }
listener.onPresenceSelected(); listener.onPresenceSelected();
} else { } else {
final StringBuilder presence = new StringBuilder(); showPresenceSelectionDialog(presences,conversation,listener);
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;
}
}
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() {
@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();
}
});
builder.create().show();
} }
} }
} }
protected void onActivityResult(int requestCode, int resultCode, private void showPresenceSelectionDialog(Presences presences, final Conversation conversation, final OnPresenceSelected listener) {
final Intent data) { 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<String, String>, Map<String, String>> typeAndName = presences.toTypeAndNameMap();
final Map<String,String> resourceTypeMap = typeAndName.first;
final Map<String,String> 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+")";
}
} else {
readableIdentities[i] = resource;
}
}
builder.setSingleChoiceItems(readableIdentities,
selectedResource.get(),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
selectedResource.set(which);
}
});
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) {
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_INVITE_TO_CONVERSATION && resultCode == RESULT_OK) { if (requestCode == REQUEST_INVITE_TO_CONVERSATION && resultCode == RESULT_OK) {
mPendingConferenceInvite = ConferenceInvite.parse(data); mPendingConferenceInvite = ConferenceInvite.parse(data);

View file

@ -21,6 +21,7 @@ import java.util.Iterator;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.regex.Pattern;
import eu.siacs.conversations.Config; import eu.siacs.conversations.Config;
import eu.siacs.conversations.R; import eu.siacs.conversations.R;
@ -31,6 +32,8 @@ import eu.siacs.conversations.xmpp.jid.Jid;
public final class CryptoHelper { public final class CryptoHelper {
public static final String FILETRANSFER = "?FILETRANSFERv1:"; public static final String FILETRANSFER = "?FILETRANSFERv1:";
private final static char[] hexArray = "0123456789abcdef".toCharArray(); 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 }; final public static byte[] ONE = new byte[] { 0, 0, 0, 1 };
public static String bytesToHex(byte[] bytes) { public static String bytesToHex(byte[] bytes) {

View file

@ -18,6 +18,7 @@ import eu.siacs.conversations.entities.ListItem;
import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.Presence; import eu.siacs.conversations.entities.Presence;
import eu.siacs.conversations.entities.Transferable; import eu.siacs.conversations.entities.Transferable;
import eu.siacs.conversations.ui.XmppActivity;
import eu.siacs.conversations.xmpp.jid.Jid; import eu.siacs.conversations.xmpp.jid.Jid;
public class UIHelper { public class UIHelper {
@ -286,4 +287,21 @@ public class UIHelper {
return new ListItem.Tag(context.getString(R.string.presence_online), 0xff259b24); 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;
}
}
} }

View file

@ -79,7 +79,7 @@
<string name="clear_histor_msg">Do you want to delete all messages within this Conversation?\n\n<b>Warning:</b> This will not influence messages stored on other devices or servers.</string> <string name="clear_histor_msg">Do you want to delete all messages within this Conversation?\n\n<b>Warning:</b> This will not influence messages stored on other devices or servers.</string>
<string name="delete_messages">Delete messages</string> <string name="delete_messages">Delete messages</string>
<string name="also_end_conversation">End this conversation afterwards</string> <string name="also_end_conversation">End this conversation afterwards</string>
<string name="choose_presence">Choose presence to contact</string> <string name="choose_presence">Choose device</string>
<string name="send_unencrypted_message">Send unencrypted message</string> <string name="send_unencrypted_message">Send unencrypted message</string>
<string name="send_message_to_x">Send message to %s</string> <string name="send_message_to_x">Send message to %s</string>
<string name="send_otr_message">Send OTR encrypted message</string> <string name="send_otr_message">Send OTR encrypted message</string>
@ -669,4 +669,9 @@
<string name="pref_use_green_background_summary">Use green background for received messages</string> <string name="pref_use_green_background_summary">Use green background for received messages</string>
<string name="unable_to_connect_to_keychain">Unable to connect to OpenKeychain</string> <string name="unable_to_connect_to_keychain">Unable to connect to OpenKeychain</string>
<string name="this_device_is_no_longer_in_use">This device is no longer in use</string> <string name="this_device_is_no_longer_in_use">This device is no longer in use</string>
<string name="type_pc">Computer</string>
<string name="type_phone">Mobile phone</string>
<string name="type_tablet">Tablet</string>
<string name="type_web">Web browser</string>
<string name="type_console">Console</string>
</resources> </resources>