better error display and additional infos (stats) for the edit account activity

iNPUTmice created

Change summary

res/layout/activity_edit_account.xml                           |  80 +
res/layout/server_info.xml                                     | 157 ----
res/values/strings.xml                                         |   3 
src/eu/siacs/conversations/entities/Account.java               | 156 ++-
src/eu/siacs/conversations/services/XmppConnectionService.java |  12 
src/eu/siacs/conversations/ui/EditAccountActivity.java         | 121 +-
src/eu/siacs/conversations/ui/ManageAccountActivity.java       |  65 -
src/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java   |   5 
src/eu/siacs/conversations/utils/UIHelper.java                 |   1 
src/eu/siacs/conversations/xmpp/XmppConnection.java            |  85 +
src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java   |   6 
11 files changed, 314 insertions(+), 377 deletions(-)

Detailed changes

res/layout/activity_edit_account.xml 🔗

@@ -5,6 +5,7 @@
     android:background="@color/primarybackground" >
 
     <LinearLayout
+        android:id="@+id/editor"
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
         android:orientation="vertical"
@@ -14,23 +15,23 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="@string/account_settings_jabber_id"
-            android:textSize="14sp"
-            android:textColor="@color/primarytext"/>
+            android:textColor="@color/primarytext"
+            android:textSize="14sp" />
 
         <AutoCompleteTextView
             android:id="@+id/account_jid"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:hint="@string/account_settings_example_jabber_id"
-            android:inputType="textEmailAddress"/>
+            android:inputType="textEmailAddress" />
 
         <TextView
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_marginTop="8dp"
             android:text="@string/account_settings_password"
-            android:textSize="14sp"
-            android:textColor="@color/primarytext"/>
+            android:textColor="@color/primarytext"
+            android:textSize="14sp" />
 
         <EditText
             android:id="@+id/account_password"
@@ -45,16 +46,16 @@
             android:layout_height="wrap_content"
             android:layout_marginTop="8dp"
             android:text="@string/register_account"
-            android:textSize="14sp"
-            android:textColor="@color/primarytext"/>
+            android:textColor="@color/primarytext"
+            android:textSize="14sp" />
 
         <TextView
             android:id="@+id/account_confirm_password_desc"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:text="@string/account_settings_confirm_password"
-            android:textSize="14sp"
             android:textColor="@color/primarytext"
+            android:textSize="14sp"
             android:visibility="gone" />
 
         <EditText
@@ -67,13 +68,74 @@
             android:visibility="gone" />
     </LinearLayout>
 
+    <LinearLayout
+        android:id="@+id/stats"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:layout_above="@+id/button_bar"
+        android:layout_alignParentLeft="true"
+        android:layout_below="@+id/editor"
+        android:layout_marginTop="8dp"
+        android:orientation="vertical"
+        android:padding="16dp"
+        android:visibility="gone">
+
+        <TextView
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:textSize="18sp"
+            android:textStyle="bold"
+            android:textColor="@color/secondarytext"
+            android:text="@string/additional_information"
+            android:gravity="center_horizontal"/>
+
+        <TableLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:stretchColumns="1"
+            android:layout_marginTop="8dp">
+
+            <TableRow
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content" >
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/server_info_session_established" />
+
+                <TextView
+                    android:id="@+id/session_est"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="right" />
+            </TableRow>
+
+            <TableRow
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content" >
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/server_info_compatibilty" />
+
+                <TextView
+                    android:id="@+id/server_compat"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="right" />
+            </TableRow>
+        </TableLayout>
+    </LinearLayout>
+
     <LinearLayout
         android:id="@+id/button_bar"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_alignParentBottom="true"
         android:layout_alignParentLeft="true"
-        android:layout_alignParentRight="true" >
+        android:layout_alignParentRight="true">
 
         <Button
             android:id="@+id/cancel_button"

res/layout/server_info.xml 🔗

@@ -1,157 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="fill_parent"
-    android:layout_height="match_parent"
-    android:padding="8dp" >
-
-    <TextView
-        android:id="@+id/stats_header"
-        style="@style/sectionHeader"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:paddingLeft="8dp"
-        android:paddingRight="8dp"
-        android:paddingBottom="8dp"
-        android:text="@string/server_info_statistics" />
-    
-    <TextView
-        android:layout_below="@+id/stats_header"
-        android:id="@+id/textView1"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:text="@string/server_info_connection_age"
-        android:textSize="18sp"/>
-     <TextView
-        android:id="@+id/connection"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignBaseline="@+id/textView1"
-        android:layout_alignBottom="@+id/textView1"
-        android:layout_alignParentRight="true"
-        android:textSize="18sp"/>
-
-    <TextView
-        android:id="@+id/textView2"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignParentLeft="true"
-        android:layout_below="@+id/textView1"
-        android:text="@string/server_info_session_age"
-        android:textSize="18sp"/>
-        <TextView
-        android:id="@+id/session"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignBaseline="@+id/textView2"
-        android:layout_alignBottom="@+id/textView2"
-        android:layout_alignParentRight="true"
-        android:textSize="18sp"/>
-
-    <TextView
-        android:id="@+id/textView3"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignParentLeft="true"
-        android:layout_below="@+id/textView2"
-        android:text="@string/server_info_packets_sent"
-        android:textSize="18sp"/>
-       <TextView
-        android:id="@+id/pcks_sent"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignBaseline="@+id/textView3"
-        android:layout_alignBottom="@+id/textView3"
-        android:layout_alignParentRight="true"
-        android:textSize="18sp"/>
-       
-    <TextView
-        android:id="@+id/textView4"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_below="@+id/textView3"
-        android:text="@string/server_info_packets_received"
-        android:textSize="18sp"/>
-    <TextView
-        android:id="@+id/pcks_received"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignBaseline="@+id/textView4"
-        android:layout_alignBottom="@+id/textView4"
-        android:layout_alignParentRight="true"
-        android:textSize="18sp"/>
-    
-    <TextView
-        android:id="@+id/textView10"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_below="@+id/textView4"
-        android:text="@string/server_info_connected_accounts"
-        android:textSize="18sp"/>
-    <TextView
-        android:id="@+id/number_presences"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignBaseline="@+id/textView10"
-        android:layout_alignBottom="@+id/textView10"
-        android:layout_alignParentRight="true"
-        android:textSize="18sp"/>
-    
-    <TextView
-        android:id="@+id/features_header"
-        android:layout_below="@+id/textView10"
-        style="@style/sectionHeader"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:padding="8dp"
-        android:text="@string/server_info_server_features" />
-
-    <TextView
-        android:layout_below="@+id/features_header"
-        android:id="@+id/textView5"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:text="@string/server_info_roster_versioning"
-        android:textSize="18sp"/>
-     <TextView
-        android:id="@+id/roster"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignBaseline="@+id/textView5"
-        android:layout_alignBottom="@+id/textView5"
-        android:layout_alignParentRight="true"
-        android:textSize="18sp"/>
-
-    <TextView
-        android:id="@+id/textView6"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignParentLeft="true"
-        android:layout_below="@+id/textView5"
-        android:text="@string/server_info_carbon_messages"
-        android:textSize="18sp"/>
-        <TextView
-        android:id="@+id/carbon"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignBaseline="@+id/textView6"
-        android:layout_alignBottom="@+id/textView6"
-        android:layout_alignParentRight="true"
-        android:textSize="18sp"/>
-
-    <TextView
-        android:id="@+id/textView7"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignParentLeft="true"
-        android:layout_below="@+id/textView6"
-        android:text="@string/server_info_stream_management"
-        android:textSize="18sp"/>
-       <TextView
-        android:id="@+id/stream"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignBaseline="@+id/textView7"
-        android:layout_alignBottom="@+id/textView7"
-        android:layout_alignParentRight="true"
-        android:textSize="18sp"/>
-</RelativeLayout>

res/values/strings.xml 🔗

@@ -284,4 +284,7 @@
     <string name="connect">Connect</string>
     <string name="account_already_exists">This account does already exist</string>
     <string name="next">Next</string>
+    <string name="server_info_compatibilty">Server compatibilty</string>
+    <string name="server_info_session_established">Current session established</string>
+    <string name="additional_information">Additional Information</string>
 </resources>

src/eu/siacs/conversations/entities/Account.java 🔗

@@ -11,6 +11,7 @@ import net.java.otr4j.crypto.OtrCryptoException;
 import org.json.JSONException;
 import org.json.JSONObject;
 
+import eu.siacs.conversations.R;
 import eu.siacs.conversations.crypto.OtrEngine;
 import eu.siacs.conversations.persistance.FileBackend;
 import eu.siacs.conversations.utils.UIHelper;
@@ -19,24 +20,23 @@ import android.content.ContentValues;
 import android.content.Context;
 import android.database.Cursor;
 import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
 
-public class Account  extends AbstractEntity{
-	
+public class Account extends AbstractEntity {
+
 	public static final String TABLENAME = "accounts";
-	
+
 	public static final String USERNAME = "username";
 	public static final String SERVER = "server";
 	public static final String PASSWORD = "password";
 	public static final String OPTIONS = "options";
 	public static final String ROSTERVERSION = "rosterversion";
 	public static final String KEYS = "keys";
-	
+
 	public static final int OPTION_USETLS = 0;
 	public static final int OPTION_DISABLED = 1;
 	public static final int OPTION_REGISTER = 2;
 	public static final int OPTION_USECOMPRESSION = 3;
-	
+
 	public static final int STATUS_CONNECTING = 0;
 	public static final int STATUS_DISABLED = -2;
 	public static final int STATUS_OFFLINE = -1;
@@ -49,7 +49,7 @@ public class Account  extends AbstractEntity{
 	public static final int STATUS_REGISTRATION_CONFLICT = 8;
 	public static final int STATUS_REGISTRATION_SUCCESSFULL = 9;
 	public static final int STATUS_REGISTRATION_NOT_SUPPORTED = 10;
-	
+
 	protected String username;
 	protected String server;
 	protected String password;
@@ -59,30 +59,33 @@ public class Account  extends AbstractEntity{
 	protected int status = -1;
 	protected JSONObject keys = new JSONObject();
 	protected String avatar;
-	
+
 	protected boolean online = false;
-	
+
 	transient OtrEngine otrEngine = null;
 	transient XmppConnection xmppConnection = null;
 	transient protected Presences presences = new Presences();
 
 	private String otrFingerprint;
-	
+
 	private Roster roster = null;
 
 	private List<Bookmark> bookmarks = new CopyOnWriteArrayList<Bookmark>();
-	
+
 	public List<Conversation> pendingConferenceJoins = new CopyOnWriteArrayList<Conversation>();
 	public List<Conversation> pendingConferenceLeaves = new CopyOnWriteArrayList<Conversation>();
-	
+
 	public Account() {
 		this.uuid = "0";
 	}
-	
+
 	public Account(String username, String server, String password) {
-		this(java.util.UUID.randomUUID().toString(),username,server,password,0,null,"");
+		this(java.util.UUID.randomUUID().toString(), username, server,
+				password, 0, null, "");
 	}
-	public Account(String uuid, String username, String server,String password, int options, String rosterVersion, String keys) {
+
+	public Account(String uuid, String username, String server,
+			String password, int options, String rosterVersion, String keys) {
 		this.uuid = uuid;
 		this.username = username;
 		this.server = server;
@@ -92,14 +95,14 @@ public class Account  extends AbstractEntity{
 		try {
 			this.keys = new JSONObject(keys);
 		} catch (JSONException e) {
-			
+
 		}
 	}
-	
+
 	public boolean isOptionSet(int option) {
 		return ((options & (1 << option)) != 0);
 	}
-	
+
 	public void setOption(int option, boolean value) {
 		if (value) {
 			this.options |= 1 << option;
@@ -107,7 +110,7 @@ public class Account  extends AbstractEntity{
 			this.options &= ~(1 << option);
 		}
 	}
-	
+
 	public String getUsername() {
 		return username;
 	}
@@ -131,11 +134,11 @@ public class Account  extends AbstractEntity{
 	public void setPassword(String password) {
 		this.password = password;
 	}
-	
+
 	public void setStatus(int status) {
 		this.status = status;
 	}
-	
+
 	public int getStatus() {
 		if (isOptionSet(OPTION_DISABLED)) {
 			return STATUS_DISABLED;
@@ -143,32 +146,34 @@ public class Account  extends AbstractEntity{
 			return this.status;
 		}
 	}
-	
+
 	public boolean errorStatus() {
 		int s = getStatus();
-		return (s == STATUS_OFFLINE || s == STATUS_SERVER_NOT_FOUND || s == STATUS_UNAUTHORIZED);
+		return (s == STATUS_REGISTRATION_FAILED || s == STATUS_REGISTRATION_CONFLICT || s == STATUS_REGISTRATION_NOT_SUPPORTED || s == STATUS_SERVER_NOT_FOUND || s == STATUS_UNAUTHORIZED);
 	}
-	
+
 	public boolean hasErrorStatus() {
-		return getStatus() > STATUS_NO_INTERNET && (getXmppConnection().getAttempt() >= 2);
+		return getStatus() > STATUS_NO_INTERNET
+				&& (getXmppConnection().getAttempt() >= 2);
 	}
-	
+
 	public void setResource(String resource) {
 		this.resource = resource;
 	}
-	
+
 	public String getResource() {
 		return this.resource;
 	}
-	
+
 	public String getJid() {
-		return username.toLowerCase(Locale.getDefault())+"@"+server.toLowerCase(Locale.getDefault());
+		return username.toLowerCase(Locale.getDefault()) + "@"
+				+ server.toLowerCase(Locale.getDefault());
 	}
-	
+
 	public JSONObject getKeys() {
 		return keys;
 	}
-	
+
 	public String getSSLFingerprint() {
 		if (keys.has("ssl_cert")) {
 			try {
@@ -180,11 +185,11 @@ public class Account  extends AbstractEntity{
 			return null;
 		}
 	}
-	
+
 	public void setSSLCertFingerprint(String fingerprint) {
 		this.setKey("ssl_cert", fingerprint);
 	}
-	
+
 	public boolean setKey(String keyName, String keyValue) {
 		try {
 			this.keys.put(keyName, keyValue);
@@ -197,16 +202,16 @@ public class Account  extends AbstractEntity{
 	@Override
 	public ContentValues getContentValues() {
 		ContentValues values = new ContentValues();
-		values.put(UUID,uuid);
+		values.put(UUID, uuid);
 		values.put(USERNAME, username);
 		values.put(SERVER, server);
 		values.put(PASSWORD, password);
-		values.put(OPTIONS,options);
-		values.put(KEYS,this.keys.toString());
-		values.put(ROSTERVERSION,rosterVersion);
+		values.put(OPTIONS, options);
+		values.put(KEYS, this.keys.toString());
+		values.put(ROSTERVERSION, rosterVersion);
 		return values;
 	}
-	
+
 	public static Account fromCursor(Cursor cursor) {
 		return new Account(cursor.getString(cursor.getColumnIndex(UUID)),
 				cursor.getString(cursor.getColumnIndex(USERNAME)),
@@ -214,14 +219,12 @@ public class Account  extends AbstractEntity{
 				cursor.getString(cursor.getColumnIndex(PASSWORD)),
 				cursor.getInt(cursor.getColumnIndex(OPTIONS)),
 				cursor.getString(cursor.getColumnIndex(ROSTERVERSION)),
-				cursor.getString(cursor.getColumnIndex(KEYS))
-				);
+				cursor.getString(cursor.getColumnIndex(KEYS)));
 	}
 
-	
 	public OtrEngine getOtrEngine(Context context) {
-		if (otrEngine==null) {
-			otrEngine = new OtrEngine(context,this);
+		if (otrEngine == null) {
+			otrEngine = new OtrEngine(context, this);
 		}
 		return this.otrEngine;
 	}
@@ -235,37 +238,39 @@ public class Account  extends AbstractEntity{
 	}
 
 	public String getFullJid() {
-		return this.getJid()+"/"+this.resource;
+		return this.getJid() + "/" + this.resource;
 	}
-	
+
 	public String getOtrFingerprint() {
 		if (this.otrFingerprint == null) {
 			try {
-				DSAPublicKey pubkey = (DSAPublicKey) this.otrEngine.getPublicKey();
+				DSAPublicKey pubkey = (DSAPublicKey) this.otrEngine
+						.getPublicKey();
 				if (pubkey == null) {
 					return null;
 				}
-				StringBuilder builder = new StringBuilder(new OtrCryptoEngineImpl().getFingerprint(pubkey));
+				StringBuilder builder = new StringBuilder(
+						new OtrCryptoEngineImpl().getFingerprint(pubkey));
 				builder.insert(8, " ");
 				builder.insert(17, " ");
 				builder.insert(26, " ");
 				builder.insert(35, " ");
 				this.otrFingerprint = builder.toString();
 			} catch (OtrCryptoException e) {
-				
+
 			}
 		}
 		return this.otrFingerprint;
 	}
 
 	public String getRosterVersion() {
-		if (this.rosterVersion==null) {
+		if (this.rosterVersion == null) {
 			return "";
 		} else {
 			return this.rosterVersion;
 		}
 	}
-	
+
 	public void setRosterVersion(String version) {
 		this.rosterVersion = version;
 	}
@@ -274,7 +279,7 @@ public class Account  extends AbstractEntity{
 		this.getOtrEngine(applicationContext);
 		return this.getOtrFingerprint();
 	}
-	
+
 	public void updatePresence(String resource, int status) {
 		this.presences.updatePresence(resource, status);
 	}
@@ -282,7 +287,7 @@ public class Account  extends AbstractEntity{
 	public void removePresence(String resource) {
 		this.presences.removePresence(resource);
 	}
-	
+
 	public void clearPresences() {
 		this.presences = new Presences();
 	}
@@ -302,9 +307,9 @@ public class Account  extends AbstractEntity{
 			return null;
 		}
 	}
-	
+
 	public Roster getRoster() {
-		if (this.roster==null) {
+		if (this.roster == null) {
 			this.roster = new Roster(this);
 		}
 		return this.roster;
@@ -313,13 +318,13 @@ public class Account  extends AbstractEntity{
 	public void setBookmarks(List<Bookmark> bookmarks) {
 		this.bookmarks = bookmarks;
 	}
-	
+
 	public List<Bookmark> getBookmarks() {
 		return this.bookmarks;
 	}
 
 	public boolean hasBookmarkFor(String conferenceJid) {
-		for(Bookmark bmark : this.bookmarks) {
+		for (Bookmark bmark : this.bookmarks) {
 			if (bmark.getJid().equals(conferenceJid)) {
 				return true;
 			}
@@ -328,10 +333,11 @@ public class Account  extends AbstractEntity{
 	}
 
 	public Bitmap getImage(Context context, int size) {
-		if (this.avatar!=null) {
+		if (this.avatar != null) {
 			Bitmap bm = FileBackend.getAvatar(this.avatar, size, context);
-			if (bm==null) {
-				return UIHelper.getContactPicture(getJid(), size, context, false);
+			if (bm == null) {
+				return UIHelper.getContactPicture(getJid(), size, context,
+						false);
 			} else {
 				return bm;
 			}
@@ -343,8 +349,38 @@ public class Account  extends AbstractEntity{
 	public void setAvatar(String filename) {
 		this.avatar = filename;
 	}
-	
+
 	public String getAvatar() {
 		return this.avatar;
 	}
+
+	public int getReadableStatusId() {
+		switch (getStatus()) {
+
+		case Account.STATUS_DISABLED:
+			return R.string.account_status_disabled;
+		case Account.STATUS_ONLINE:
+			return R.string.account_status_online;
+		case Account.STATUS_CONNECTING:
+			return R.string.account_status_connecting;
+		case Account.STATUS_OFFLINE:
+			return R.string.account_status_offline;
+		case Account.STATUS_UNAUTHORIZED:
+			return R.string.account_status_unauthorized;
+		case Account.STATUS_SERVER_NOT_FOUND:
+			return R.string.account_status_not_found;
+		case Account.STATUS_NO_INTERNET:
+			return R.string.account_status_no_internet;
+		case Account.STATUS_REGISTRATION_FAILED:
+			return R.string.account_status_regis_fail;
+		case Account.STATUS_REGISTRATION_CONFLICT:
+			return R.string.account_status_regis_conflict;
+		case Account.STATUS_REGISTRATION_SUCCESSFULL:
+			return R.string.account_status_regis_success;
+		case Account.STATUS_REGISTRATION_NOT_SUPPORTED:
+			return R.string.account_status_regis_not_sup;
+		default:
+			return R.string.account_status_unknown;
+		}
+	}
 }

src/eu/siacs/conversations/services/XmppConnectionService.java 🔗

@@ -183,7 +183,7 @@ public class XmppConnectionService extends Service {
 						+ "s for the "
 						+ (account.getXmppConnection().getAttempt() + 1)
 						+ " time");
-				scheduleWakeupCall(next, false);
+				scheduleWakeupCall((int) (next * 1.2), false);
 			}
 			UIHelper.showErrorNotification(getApplicationContext(),
 					getAccounts());
@@ -317,15 +317,13 @@ public class XmppConnectionService extends Service {
 						}
 					}
 					if (account.getStatus() == Account.STATUS_ONLINE) {
-						long lastReceived = account.getXmppConnection().lastPaketReceived;
-						long lastSent = account.getXmppConnection().lastPingSent;
+						long lastReceived = account.getXmppConnection().getLastPacketReceived();
+						long lastSent = account.getXmppConnection().getLastPingSent();
 						if (lastSent - lastReceived >= PING_TIMEOUT * 1000) {
 							Log.d(LOGTAG, account.getJid() + ": ping timeout");
 							this.reconnectAccount(account, true);
 						} else if (SystemClock.elapsedRealtime() - lastReceived >= PING_MIN_INTERVAL * 1000) {
 							account.getXmppConnection().sendPing();
-							account.getXmppConnection().lastPingSent = SystemClock
-									.elapsedRealtime();
 							this.scheduleWakeupCall(2, false);
 						}
 					} else if (account.getStatus() == Account.STATUS_OFFLINE) {
@@ -333,12 +331,10 @@ public class XmppConnectionService extends Service {
 							account.setXmppConnection(this
 									.createConnection(account));
 						}
-						account.getXmppConnection().lastPingSent = SystemClock
-								.elapsedRealtime();
 						new Thread(account.getXmppConnection()).start();
 					} else if ((account.getStatus() == Account.STATUS_CONNECTING)
 							&& ((SystemClock.elapsedRealtime() - account
-									.getXmppConnection().lastConnect) / 1000 >= CONNECT_TIMEOUT)) {
+									.getXmppConnection().getLastConnect()) / 1000 >= CONNECT_TIMEOUT)) {
 						Log.d(LOGTAG, account.getJid()
 								+ ": time out during connect reconnecting");
 						reconnectAccount(account, true);

src/eu/siacs/conversations/ui/EditAccountActivity.java 🔗

@@ -12,11 +12,15 @@ import android.widget.Button;
 import android.widget.CheckBox;
 import android.widget.CompoundButton;
 import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.TableLayout;
 import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.TextView;
 import eu.siacs.conversations.R;
 import eu.siacs.conversations.entities.Account;
 import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate;
 import eu.siacs.conversations.ui.adapter.KnownHostsAdapter;
+import eu.siacs.conversations.utils.UIHelper;
 import eu.siacs.conversations.utils.Validator;
 import eu.siacs.conversations.xmpp.pep.Avatar;
 
@@ -29,18 +33,20 @@ public class EditAccountActivity extends XmppActivity {
 	private Button mCancelButton;
 	private Button mSaveButton;
 
+	private LinearLayout mStats;
+	private TextView mServerCompat;
+	private TextView mSessionEst;
+
 	private String jidToEdit;
 	private Account mAccount;
 
-	private boolean mUserInputIsValid = false;
 	private boolean mFetchingAvatar = false;
-	
+
 	private OnClickListener mSaveButtonClickListener = new OnClickListener() {
 
 		@Override
 		public void onClick(View v) {
-			if (mAccount != null && mAccount.errorStatus()
-					&& !mUserInputIsValid) {
+			if (mAccount != null && mAccount.errorStatus()) {
 				xmppConnectionService.reconnectAccount(mAccount, true);
 				return;
 			}
@@ -66,11 +72,14 @@ public class EditAccountActivity extends XmppActivity {
 				mAccount.setPassword(password);
 				mAccount.setUsername(username);
 				mAccount.setServer(server);
-				mAccount.setOption(Account.OPTION_REGISTER, mRegisterNew.isChecked());
+				mAccount.setOption(Account.OPTION_REGISTER,
+						mRegisterNew.isChecked());
 				xmppConnectionService.updateAccount(mAccount);
 			} else {
-				if (xmppConnectionService.findAccountByJid(mAccountJid.getText().toString())!=null) {
-					mAccountJid.setError(getString(R.string.account_already_exists));
+				if (xmppConnectionService.findAccountByJid(mAccountJid
+						.getText().toString()) != null) {
+					mAccountJid
+							.setError(getString(R.string.account_already_exists));
 					return;
 				}
 				mAccount = new Account(username, server, password);
@@ -84,7 +93,6 @@ public class EditAccountActivity extends XmppActivity {
 			if (jidToEdit != null) {
 				finish();
 			} else {
-				mUserInputIsValid = false;
 				updateSaveButton();
 				updateAccountInformation();
 			}
@@ -98,24 +106,6 @@ public class EditAccountActivity extends XmppActivity {
 			finish();
 		}
 	};
-	private TextWatcher mTextWatcher = new TextWatcher() {
-
-		@Override
-		public void onTextChanged(CharSequence s, int start, int before,
-				int count) {
-			mUserInputIsValid = inputDataDiffersFromAccount() && Validator.isValidJid(mAccountJid.getText().toString());
-			updateSaveButton();
-		}
-
-		@Override
-		public void beforeTextChanged(CharSequence s, int start, int count,
-				int after) {
-		}
-
-		@Override
-		public void afterTextChanged(Editable s) {
-		}
-	};
 	private OnAccountUpdate mOnAccountUpdateListener = new OnAccountUpdate() {
 
 		@Override
@@ -124,10 +114,15 @@ public class EditAccountActivity extends XmppActivity {
 
 				@Override
 				public void run() {
-					if (jidToEdit==null && mAccount!=null && mAccount.getStatus() == Account.STATUS_ONLINE) {
+					if (mAccount != null) {
+						updateAccountInformation();
+					}
+					if (jidToEdit == null && mAccount != null
+							&& mAccount.getStatus() == Account.STATUS_ONLINE) {
 						if (!mFetchingAvatar) {
 							mFetchingAvatar = true;
-							xmppConnectionService.checkForAvatar(mAccount, mAvatarFetchCallback);
+							xmppConnectionService.checkForAvatar(mAccount,
+									mAvatarFetchCallback);
 						}
 					} else {
 						updateSaveButton();
@@ -137,33 +132,36 @@ public class EditAccountActivity extends XmppActivity {
 		}
 	};
 	private UiCallback<Avatar> mAvatarFetchCallback = new UiCallback<Avatar>() {
-		
+
 		@Override
 		public void userInputRequried(PendingIntent pi, Avatar avatar) {
 			finishInitialSetup(avatar);
 		}
-		
+
 		@Override
 		public void success(Avatar avatar) {
 			finishInitialSetup(avatar);
 		}
-		
+
 		@Override
 		public void error(int errorCode, Avatar avatar) {
 			finishInitialSetup(avatar);
 		}
 	};
+	private KnownHostsAdapter mKnownHostsAdapter;
 
 	protected void finishInitialSetup(final Avatar avatar) {
 		runOnUiThread(new Runnable() {
-			
+
 			@Override
 			public void run() {
 				Intent intent;
-				if (avatar!=null) {
-					intent = new Intent(getApplicationContext(), StartConversationActivity.class);
+				if (avatar != null) {
+					intent = new Intent(getApplicationContext(),
+							StartConversationActivity.class);
 				} else {
-					intent = new Intent(getApplicationContext(), PublishProfilePictureActivity.class);
+					intent = new Intent(getApplicationContext(),
+							PublishProfilePictureActivity.class);
 					intent.putExtra("account", mAccount.getJid());
 				}
 				startActivity(intent);
@@ -171,7 +169,7 @@ public class EditAccountActivity extends XmppActivity {
 			}
 		});
 	}
-	
+
 	protected boolean inputDataDiffersFromAccount() {
 		if (mAccount == null) {
 			return true;
@@ -186,29 +184,15 @@ public class EditAccountActivity extends XmppActivity {
 
 	protected void updateSaveButton() {
 		if (mAccount != null
-				&& mAccount.getStatus() == Account.STATUS_CONNECTING
-				&& !mUserInputIsValid) {
+				&& mAccount.getStatus() == Account.STATUS_CONNECTING) {
 			this.mSaveButton.setEnabled(false);
 			this.mSaveButton.setTextColor(getSecondaryTextColor());
 			this.mSaveButton.setText(R.string.account_status_connecting);
-		} else if (mAccount != null && mAccount.errorStatus()
-				&& !mUserInputIsValid) {
-			this.mSaveButton.setEnabled(true);
-			this.mSaveButton.setTextColor(getPrimaryTextColor());
-			this.mSaveButton.setText(R.string.connect);
-		} else if (mUserInputIsValid) {
+		} else {
 			this.mSaveButton.setEnabled(true);
 			this.mSaveButton.setTextColor(getPrimaryTextColor());
-			if (jidToEdit!=null) {
-				this.mSaveButton.setText(R.string.save);
-			} else {
-				this.mSaveButton.setText(R.string.next);
-			}
-		} else {
-			this.mSaveButton.setEnabled(false);
-			this.mSaveButton.setTextColor(getSecondaryTextColor());
-			if (jidToEdit!=null) {
-				this.mSaveButton.setText(R.string.save);
+			if (jidToEdit != null) {
+				this.mSaveButton.setText(R.string.connect);
 			} else {
 				this.mSaveButton.setText(R.string.next);
 			}
@@ -223,6 +207,9 @@ public class EditAccountActivity extends XmppActivity {
 		this.mPassword = (EditText) findViewById(R.id.account_password);
 		this.mPasswordConfirm = (EditText) findViewById(R.id.account_password_confirm);
 		this.mRegisterNew = (CheckBox) findViewById(R.id.account_register_new);
+		this.mStats = (LinearLayout) findViewById(R.id.stats);
+		this.mSessionEst = (TextView) findViewById(R.id.session_est);
+		this.mServerCompat = (TextView) findViewById(R.id.server_compat);
 		this.mSaveButton = (Button) findViewById(R.id.save_button);
 		this.mCancelButton = (Button) findViewById(R.id.cancel_button);
 		this.mSaveButton.setOnClickListener(this.mSaveButtonClickListener);
@@ -238,12 +225,9 @@ public class EditAccountActivity extends XmppActivity {
 						} else {
 							mPasswordConfirm.setVisibility(View.GONE);
 						}
-						mUserInputIsValid = inputDataDiffersFromAccount() && Validator.isValidJid(mAccountJid.getText().toString());
 						updateSaveButton();
 					}
 				});
-		this.mAccountJid.addTextChangedListener(this.mTextWatcher);
-		this.mPassword.addTextChangedListener(this.mTextWatcher);
 	}
 
 	@Override
@@ -262,6 +246,9 @@ public class EditAccountActivity extends XmppActivity {
 
 	@Override
 	protected void onBackendConnected() {
+		this.mKnownHostsAdapter = new KnownHostsAdapter(this,
+				android.R.layout.simple_list_item_1,
+				xmppConnectionService.getKnownHosts());
 		this.xmppConnectionService
 				.setOnAccountListChangedListener(this.mOnAccountUpdateListener);
 		this.mAccountJid.setAdapter(null);
@@ -273,9 +260,7 @@ public class EditAccountActivity extends XmppActivity {
 			getActionBar().setDisplayShowHomeEnabled(false);
 			this.mCancelButton.setEnabled(false);
 		}
-		this.mAccountJid.setAdapter(new KnownHostsAdapter(this,
-				android.R.layout.simple_list_item_1, xmppConnectionService
-						.getKnownHosts()));
+		this.mAccountJid.setAdapter(this.mKnownHostsAdapter);
 		updateSaveButton();
 	}
 
@@ -290,5 +275,21 @@ public class EditAccountActivity extends XmppActivity {
 			this.mRegisterNew.setVisibility(View.GONE);
 			this.mRegisterNew.setChecked(false);
 		}
+		if (this.mAccount.getStatus() == Account.STATUS_ONLINE) {
+			this.mStats.setVisibility(View.VISIBLE);
+			this.mSessionEst.setText(UIHelper.readableTimeDifference(
+					getApplicationContext(), this.mAccount.getXmppConnection()
+							.getLastSessionEstablished()));
+			this.mServerCompat.setText(this.mAccount.getXmppConnection()
+					.getFeatures().getCompatibility()
+					+ "%");
+		} else {
+			if (this.mAccount.errorStatus()) {
+				this.mAccountJid.setError(getString(this.mAccount
+						.getReadableStatusId()));
+				this.mAccountJid.requestFocus();
+			}
+			this.mStats.setVisibility(View.GONE);
+		}
 	}
 }

src/eu/siacs/conversations/ui/ManageAccountActivity.java 🔗

@@ -146,71 +146,6 @@ public class ManageAccountActivity extends XmppActivity {
 				builder.setView(view);
 				builder.setPositiveButton(getString(R.string.done), null);
 				builder.create().show();
-			} else if (item.getItemId() == R.id.mgmt_account_info) {
-				AlertDialog.Builder builder = new AlertDialog.Builder(activity);
-				builder.setTitle(getString(R.string.account_info));
-				if (selectedAccountForActionMode.getStatus() == Account.STATUS_ONLINE) {
-					XmppConnection xmpp = selectedAccountForActionMode
-							.getXmppConnection();
-					long connectionAge = (SystemClock.elapsedRealtime() - xmpp.lastConnect) / 60000;
-					long sessionAge = (SystemClock.elapsedRealtime() - xmpp.lastSessionStarted) / 60000;
-					long connectionAgeHours = connectionAge / 60;
-					long sessionAgeHours = sessionAge / 60;
-					View view = (View) getLayoutInflater().inflate(
-							R.layout.server_info, null);
-					TextView connection = (TextView) view
-							.findViewById(R.id.connection);
-					TextView session = (TextView) view
-							.findViewById(R.id.session);
-					TextView pcks_sent = (TextView) view
-							.findViewById(R.id.pcks_sent);
-					TextView pcks_received = (TextView) view
-							.findViewById(R.id.pcks_received);
-					TextView carbon = (TextView) view.findViewById(R.id.carbon);
-					TextView stream = (TextView) view.findViewById(R.id.stream);
-					TextView roster = (TextView) view.findViewById(R.id.roster);
-					TextView presences = (TextView) view
-							.findViewById(R.id.number_presences);
-					presences.setText(selectedAccountForActionMode
-							.countPresences() + "");
-					pcks_received.setText("" + xmpp.getReceivedStanzas());
-					pcks_sent.setText("" + xmpp.getSentStanzas());
-					if (connectionAgeHours >= 2) {
-						connection.setText(connectionAgeHours + " "
-								+ getString(R.string.hours));
-					} else {
-						connection.setText(connectionAge + " "
-								+ getString(R.string.mins));
-					}
-					if (xmpp.getFeatures().sm()) {
-						if (sessionAgeHours >= 2) {
-							session.setText(sessionAgeHours + " "
-									+ getString(R.string.hours));
-						} else {
-							session.setText(sessionAge + " "
-									+ getString(R.string.mins));
-						}
-						stream.setText(getString(R.string.yes));
-					} else {
-						stream.setText(getString(R.string.no));
-						session.setText(connection.getText());
-					}
-					if (xmpp.getFeatures().carbons()) {
-						carbon.setText(getString(R.string.yes));
-					} else {
-						carbon.setText(getString(R.string.no));
-					}
-					if (xmpp.getFeatures().rosterVersioning()) {
-						roster.setText(getString(R.string.yes));
-					} else {
-						roster.setText(getString(R.string.no));
-					}
-					builder.setView(view);
-				} else {
-					builder.setMessage(getString(R.string.mgmt_account_account_offline));
-				}
-				builder.setPositiveButton(getString(R.string.hide), null);
-				builder.create().show();
 			}
 			return true;
 		}

src/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java 🔗

@@ -23,7 +23,10 @@ public class KnownHostsAdapter extends ArrayAdapter<String> {
 					}
 				} else if (split.length == 2) {
 					for (String domain : domains) {
-						if (domain.contains(split[1])) {
+						if (domain.contentEquals(split[1])) {
+							suggestions.clear();
+							break;
+						} else if (domain.contains(split[1])) {
 							suggestions.add(split[0].toLowerCase(Locale.getDefault()) + "@" + domain);
 						}
 					}

src/eu/siacs/conversations/utils/UIHelper.java 🔗

@@ -15,7 +15,6 @@ import eu.siacs.conversations.entities.Contact;
 import eu.siacs.conversations.entities.Conversation;
 import eu.siacs.conversations.entities.Message;
 import eu.siacs.conversations.entities.MucOptions.User;
-import eu.siacs.conversations.persistance.FileBackend;
 import eu.siacs.conversations.ui.ConversationActivity;
 import eu.siacs.conversations.ui.ManageAccountActivity;
 import android.app.Activity;

src/eu/siacs/conversations/xmpp/XmppConnection.java 🔗

@@ -74,14 +74,16 @@ public class XmppConnection implements Runnable {
 
 	private String streamId = null;
 	private int smVersion = 3;
+	
+	private boolean usingCompression = false;
 
 	private int stanzasReceived = 0;
 	private int stanzasSent = 0;
 
-	public long lastPaketReceived = 0;
-	public long lastPingSent = 0;
-	public long lastConnect = 0;
-	public long lastSessionStarted = 0;
+	private long lastPaketReceived = 0;
+	private long lastPingSent = 0;
+	private long lastConnect = 0;
+	private long lastSessionStarted = 0;
 
 	private int attempt = 0;
 
@@ -127,7 +129,9 @@ public class XmppConnection implements Runnable {
 
 	protected void connect() {
 		Log.d(LOGTAG, account.getJid() + ": connecting");
+		usingCompression = false;
 		lastConnect = SystemClock.elapsedRealtime();
+		lastPingSent = SystemClock.elapsedRealtime();
 		this.attempt++;
 		try {
 			shouldAuthenticate = shouldBind = !account
@@ -417,6 +421,7 @@ public class XmppConnection implements Runnable {
 
 		sendStartStream();
 		Log.d(LOGTAG, account.getJid() + ": compression enabled");
+		usingCompression = true;
 		processStream(tagReader.readTag());
 	}
 
@@ -766,6 +771,7 @@ public class XmppConnection implements Runnable {
 			iq.addChild("ping", "urn:xmpp:ping");
 			this.sendIqPacket(iq, null);
 		}
+		this.lastPingSent = SystemClock.elapsedRealtime();
 	}
 
 	public void setOnMessagePacketReceivedListener(
@@ -850,15 +856,7 @@ public class XmppConnection implements Runnable {
 	public void r() {
 		this.tagWriter.writeStanzaAsync(new RequestPacket(smVersion));
 	}
-
-	public int getReceivedStanzas() {
-		return this.stanzasReceived;
-	}
-
-	public int getSentStanzas() {
-		return this.stanzasSent;
-	}
-
+	
 	public String getMucServer() {
 		return findDiscoItemByFeature("http://jabber.org/protocol/muc");
 	}
@@ -913,5 +911,66 @@ public class XmppConnection implements Runnable {
 				return connection.streamFeatures.hasChild("ver");
 			}
 		}
+		
+		public boolean streamhost() {
+			return connection.findDiscoItemByFeature("http://jabber.org/protocol/bytestreams") != null;
+		}
+		
+		public boolean compression() {
+			return connection.usingCompression;
+		}
+		
+		public int getCompatibility() {
+			int hit = 0;
+			int miss = 0;
+			if (carbons()) {
+				++hit;
+			} else {
+				++miss;
+			}
+			if (sm()) {
+				++hit;
+			} else {
+				++miss;
+			}
+			if (pubsub()) {
+				++hit;
+			} else {
+				++miss;
+			}
+			if (streamhost()) {
+				++hit;
+			} else {
+				++miss;
+			}
+			if (compression()) {
+				++hit;
+			} else {
+				++miss;
+			}
+			return (int) (((float) hit) / (hit + miss) * 100);
+		}
+	}
+
+	public long getLastSessionEstablished() {
+		long diff;
+		if (this.lastSessionStarted == 0) {
+			diff = SystemClock.elapsedRealtime() - this.lastConnect;
+		} else {
+			diff = SystemClock.elapsedRealtime() - this.lastSessionStarted;
+		}
+		return System.currentTimeMillis() - diff;
+	}
+	
+	public long getLastConnect() {
+		return this.lastConnect;
+	}
+	
+	public long getLastPingSent() {
+		return this.lastPingSent;
+	}
+	
+	public long getLastPacketReceived() {
+		return this.lastPaketReceived;
 	}
 }

src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java 🔗

@@ -2,11 +2,11 @@ package eu.siacs.conversations.xmpp.jingle;
 
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
 
 import android.content.Intent;
 import android.graphics.BitmapFactory;
@@ -48,7 +48,7 @@ public class JingleConnection {
 	private String initiator;
 	private String responder;
 	private List<JingleCandidate> candidates = new ArrayList<JingleCandidate>();
-	private HashMap<String, JingleSocks5Transport> connections = new HashMap<String, JingleSocks5Transport>();
+	private ConcurrentHashMap<String, JingleSocks5Transport> connections = new ConcurrentHashMap<String, JingleSocks5Transport>();
 
 	private String transportId;
 	private Element fileOffer;
@@ -696,6 +696,7 @@ public class JingleConnection {
 	}
 
 	public void cancel() {
+		this.status = STATUS_CANCELED;
 		this.disconnect();
 		if (this.message != null) {
 			if (this.responder.equals(account.getFullJid())) {
@@ -711,7 +712,6 @@ public class JingleConnection {
 				}
 			}
 		}
-		this.status = STATUS_CANCELED;
 		this.mJingleConnectionManager.finishConnection(this);
 	}