account management

Daniel Gultsch created

Change summary

AndroidManifest.xml                                     |   3 
gen/de/gultsch/chat/R.java                              | 126 ++++--
res/layout/account_row.xml                              |  54 +++
res/layout/edit_account_dialog.xml                      | 143 ++++++++
res/layout/manage_accounts.xml                          |  14 
res/menu/manageaccounts.xml                             |  11 
res/values/strings.xml                                  |   1 
res/values/styles.xml                                   |   2 
src/de/gultsch/chat/entities/Account.java               |  74 +++
src/de/gultsch/chat/entities/Message.java               |   2 
src/de/gultsch/chat/persistance/DatabaseBackend.java    |  33 +
src/de/gultsch/chat/services/XmppConnectionService.java |  16 
src/de/gultsch/chat/ui/ConversationFragment.java        |  22 
src/de/gultsch/chat/ui/EditAccount.java                 | 196 +++++++++++
src/de/gultsch/chat/ui/ManageAccountActivity.java       | 139 +++++++
src/de/gultsch/chat/ui/NewConversationActivity.java     |  16 
src/de/gultsch/chat/utils/Validator.java                |  14 
17 files changed, 785 insertions(+), 81 deletions(-)

Detailed changes

AndroidManifest.xml 🔗

@@ -41,8 +41,7 @@
             android:name="de.gultsch.chat.ui.NewConversationActivity"
             android:label="@string/title_activity_new_conversation"
             android:parentActivityName="de.gultsch.chat.ui.ConversationActivity"
-            android:windowSoftInputMode="stateHidden"
-            android:noHistory="true">
+            android:windowSoftInputMode="stateHidden">
             <meta-data
                 android:name="android.support.PARENT_ACTIVITY"
                 android:value="de.gultsch.chat.ui.ConversationActivity" />

gen/de/gultsch/chat/R.java 🔗

@@ -27,73 +27,97 @@ public final class R {
     public static final class drawable {
         public static final int es_slidingpane_shadow=0x7f020000;
         public static final int ic_action_add=0x7f020001;
-        public static final int ic_action_send=0x7f020002;
-        public static final int ic_action_send_now=0x7f020003;
-        public static final int ic_action_unsecure=0x7f020004;
-        public static final int ic_launcher=0x7f020005;
-        public static final int ic_profile=0x7f020006;
-        public static final int message_border=0x7f020007;
-        public static final int profilemock=0x7f020008;
-        public static final int section_header=0x7f020009;
+        public static final int ic_action_add_person=0x7f020002;
+        public static final int ic_action_send=0x7f020003;
+        public static final int ic_action_send_now=0x7f020004;
+        public static final int ic_action_unsecure=0x7f020005;
+        public static final int ic_launcher=0x7f020006;
+        public static final int ic_profile=0x7f020007;
+        public static final int message_border=0x7f020008;
+        public static final int profilemock=0x7f020009;
+        public static final int section_header=0x7f02000a;
     }
     public static final class id {
-        public static final int action_accounts=0x7f0a001e;
-        public static final int action_add=0x7f0a001a;
-        public static final int action_archive=0x7f0a001d;
-        public static final int action_details=0x7f0a001c;
-        public static final int action_security=0x7f0a001b;
-        public static final int action_settings=0x7f0a001f;
-        public static final int contact_display_name=0x7f0a0009;
-        public static final int contact_divider=0x7f0a000b;
-        public static final int contact_jid=0x7f0a000a;
-        public static final int contact_photo=0x7f0a0008;
-        public static final int conversation_image=0x7f0a000c;
-        public static final int conversation_lastmsg=0x7f0a000e;
-        public static final int conversation_lastupdate=0x7f0a000f;
-        public static final int conversation_name=0x7f0a000d;
-        public static final int create_new_contact=0x7f0a0007;
-        public static final int jabber_contacts=0x7f0a0005;
-        public static final int jabber_contacts_header=0x7f0a0004;
-        public static final int list=0x7f0a0015;
-        public static final int message_body=0x7f0a0018;
-        public static final int message_photo=0x7f0a0017;
-        public static final int message_time=0x7f0a0019;
-        public static final int messages_view=0x7f0a0013;
-        public static final int new_contact_header=0x7f0a0006;
-        public static final int new_conversation_search=0x7f0a0000;
-        public static final int phone_contacts=0x7f0a0003;
-        public static final int phone_contacts_header=0x7f0a0002;
-        public static final int scrollView1=0x7f0a0001;
-        public static final int selected_conversation=0x7f0a0016;
-        public static final int slidingpanelayout=0x7f0a0014;
-        public static final int textSendButton=0x7f0a0012;
-        public static final int textinput=0x7f0a0011;
-        public static final int textsend=0x7f0a0010;
+        public static final int account_confirm_password_desc=0x7f0a0017;
+        public static final int account_jid=0x7f0a0000;
+        public static final int account_list=0x7f0a0027;
+        public static final int account_password=0x7f0a0015;
+        public static final int account_password_confirm2=0x7f0a0018;
+        public static final int account_server=0x7f0a001d;
+        public static final int account_show_advanced=0x7f0a0019;
+        public static final int account_status=0x7f0a0002;
+        public static final int account_username=0x7f0a0013;
+        public static final int action_accounts=0x7f0a002f;
+        public static final int action_add=0x7f0a002b;
+        public static final int action_add_account=0x7f0a0031;
+        public static final int action_archive=0x7f0a002e;
+        public static final int action_details=0x7f0a002d;
+        public static final int action_security=0x7f0a002c;
+        public static final int action_settings=0x7f0a0030;
+        public static final int advanced_options=0x7f0a001a;
+        public static final int contact_display_name=0x7f0a000c;
+        public static final int contact_divider=0x7f0a000e;
+        public static final int contact_jid=0x7f0a000d;
+        public static final int contact_photo=0x7f0a000b;
+        public static final int conversation_image=0x7f0a000f;
+        public static final int conversation_lastmsg=0x7f0a0011;
+        public static final int conversation_lastupdate=0x7f0a0012;
+        public static final int conversation_name=0x7f0a0010;
+        public static final int create_new_contact=0x7f0a000a;
+        public static final int editText3=0x7f0a001f;
+        public static final int edit_account_register_new=0x7f0a0016;
+        public static final int jabber_contacts=0x7f0a0008;
+        public static final int jabber_contacts_header=0x7f0a0007;
+        public static final int list=0x7f0a0025;
+        public static final int message_body=0x7f0a0029;
+        public static final int message_photo=0x7f0a0028;
+        public static final int message_time=0x7f0a002a;
+        public static final int messages_view=0x7f0a0023;
+        public static final int new_contact_header=0x7f0a0009;
+        public static final int new_conversation_search=0x7f0a0003;
+        public static final int phone_contacts=0x7f0a0006;
+        public static final int phone_contacts_header=0x7f0a0005;
+        public static final int scrollView1=0x7f0a0004;
+        public static final int selected_conversation=0x7f0a0026;
+        public static final int server_input_layout=0x7f0a001b;
+        public static final int slidingpanelayout=0x7f0a0024;
+        public static final int textSendButton=0x7f0a0022;
+        public static final int textView1=0x7f0a0014;
+        public static final int textView2=0x7f0a0001;
+        public static final int textView3=0x7f0a001c;
+        public static final int textView4=0x7f0a001e;
+        public static final int textinput=0x7f0a0021;
+        public static final int textsend=0x7f0a0020;
     }
     public static final class layout {
-        public static final int activity_new_conversation=0x7f030000;
-        public static final int contact=0x7f030001;
-        public static final int conversation_list_row=0x7f030002;
-        public static final int fragment_conversation=0x7f030003;
-        public static final int fragment_conversations_overview=0x7f030004;
-        public static final int message_recieved=0x7f030005;
-        public static final int message_sent=0x7f030006;
+        public static final int account_row=0x7f030000;
+        public static final int activity_new_conversation=0x7f030001;
+        public static final int contact=0x7f030002;
+        public static final int conversation_list_row=0x7f030003;
+        public static final int edit_account_dialog=0x7f030004;
+        public static final int fragment_conversation=0x7f030005;
+        public static final int fragment_conversations_overview=0x7f030006;
+        public static final int manage_accounts=0x7f030007;
+        public static final int message_recieved=0x7f030008;
+        public static final int message_sent=0x7f030009;
     }
     public static final class menu {
         public static final int conversations=0x7f090000;
-        public static final int newconversation=0x7f090001;
+        public static final int manageaccounts=0x7f090001;
+        public static final int newconversation=0x7f090002;
     }
     public static final class string {
         public static final int action_accounts=0x7f070003;
         public static final int action_add=0x7f070002;
+        public static final int action_add_account=0x7f070007;
         public static final int action_archive=0x7f070004;
         public static final int action_details=0x7f070005;
         public static final int action_secure=0x7f070006;
         public static final int action_settings=0x7f070001;
         public static final int app_name=0x7f070000;
-        public static final int just_now=0x7f070008;
-        public static final int sending=0x7f070009;
-        public static final int title_activity_new_conversation=0x7f070007;
+        public static final int just_now=0x7f070009;
+        public static final int sending=0x7f07000a;
+        public static final int title_activity_new_conversation=0x7f070008;
     }
     public static final class style {
         /** 

res/layout/account_row.xml 🔗

@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:padding="8dp">
+
+ 
+
+    <LinearLayout
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        android:layout_alignParentLeft="true"
+        android:layout_alignParentTop="true"
+        android:orientation="vertical">
+
+        <TextView
+            android:id="@+id/account_jid"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="inputmice@jabber.ccc.de"
+            android:textSize="20sp"
+            android:singleLine="true"
+	        android:scrollHorizontally="false"/>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:paddingTop="3dp">
+
+            <TextView
+                android:id="@+id/textView2"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Status: "
+                android:textStyle="bold"
+               	android:textSize="14sp" />
+
+            <TextView
+                android:id="@+id/account_status"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:textColor="#669900"
+                android:text="Online"
+                android:textStyle="bold"
+                android:textSize="14sp"/>
+
+        </LinearLayout>
+
+    </LinearLayout>
+
+    
+</RelativeLayout>

res/layout/edit_account_dialog.xml 🔗

@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:padding="8dp">
+
+    <TextView
+        android:id="@+id/textView2"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textSize="14sp"
+        android:text="Jabber ID:" />
+
+    <EditText
+        android:id="@+id/account_username"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:ems="10"
+        android:inputType="textEmailAddress"
+        android:visibility="gone"
+        android:hint="Username">
+        </EditText>
+    
+   <EditText
+        android:id="@+id/account_jid"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:ems="10"
+        android:inputType="textEmailAddress"
+        android:hint="username@jabber.example.com">
+
+
+    </EditText>
+    
+       
+      <TextView
+        android:paddingTop="8dp"
+        android:id="@+id/textView1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Password:"
+        android:textSize="14sp"/>
+
+    <EditText
+        android:id="@+id/account_password"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:ems="10"
+        android:inputType="textPassword"
+        android:hint="Password" 
+        android:fontFamily="sans-serif" />
+
+  
+    <CheckBox
+        android:id="@+id/edit_account_register_new"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Register a new account on server"/>
+
+    
+        <TextView
+        android:paddingTop="8dp"
+        android:id="@+id/account_confirm_password_desc"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Confirm password:"
+        android:textSize="14sp"
+        android:visibility="gone"/>
+    
+    <EditText
+        android:id="@+id/account_password_confirm2"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:ems="10"
+        android:inputType="textPassword"
+        android:hint="Confirm password" 
+        android:visibility="gone"
+        android:fontFamily="sans-serif" />
+
+    <CheckBox
+        android:id="@+id/account_show_advanced"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Show advanced options" />
+    
+    <RelativeLayout
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:id="@+id/advanced_options"
+        android:visibility="gone">
+
+         <LinearLayout
+             android:id="@+id/server_input_layout"
+             android:layout_width="wrap_content"
+             android:layout_height="wrap_content"
+             android:orientation="vertical" >
+             
+                <TextView
+        android:paddingTop="8dp"
+        android:id="@+id/textView3"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Server:"
+        android:textSize="14sp"/>
+             
+        <EditText
+            android:id="@+id/account_server"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:ems="10"
+            android:hint="Server"
+            android:inputType="textUri"/>
+
+        </LinearLayout>
+        
+         <LinearLayout
+             android:layout_alignParentRight="true"
+             android:layout_width="144dp"
+             android:layout_height="wrap_content"
+             android:orientation="vertical"
+             android:layout_toRightOf="@+id/server_input_layout">
+             
+                <TextView
+        android:paddingTop="8dp"
+        android:id="@+id/textView4"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Port:"
+        android:textSize="14sp"/>
+        
+        <EditText
+            android:id="@+id/editText3"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:ems="10"
+            android:hint="Port"
+            android:inputType="number"
+            android:text="5222"/>
+
+        </LinearLayout>
+    </RelativeLayout>
+</LinearLayout>

res/layout/manage_accounts.xml 🔗

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent" >
+
+    <ListView
+        android:id="@+id/account_list"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        tools:listitem="@layout/account_row">
+    </ListView>
+
+</LinearLayout>

res/menu/manageaccounts.xml 🔗

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item android:id="@+id/action_add_account"
+        android:showAsAction="always"
+        android:title="@string/action_add_account"/>
+ <item
+        android:id="@+id/action_settings"
+        android:orderInCategory="100"
+        android:showAsAction="never"
+        android:title="@string/action_settings"/>
+</menu>

res/values/strings.xml 🔗

@@ -8,6 +8,7 @@
     <string name="action_archive">Archive conversation</string>
     <string name="action_details">Show details</string>
     <string name="action_secure">Secure conversation</string>
+    <string name="action_add_account">Add account</string>
     <string name="title_activity_new_conversation">New Conversation</string>
     <string name="just_now">just now</string>
     <string name="sending">sending&#8230;</string>

res/values/styles.xml 🔗

@@ -33,5 +33,5 @@
     	<item name="android:layout_height">1.5dp</item>
     	<item name="android:background">#b7b7b7</item>
 	</style>
-     
+	
 </resources>

src/de/gultsch/chat/entities/Account.java 🔗

@@ -1,18 +1,86 @@
 package de.gultsch.chat.entities;
 
 import android.content.ContentValues;
+import android.database.Cursor;
+import android.util.Log;
 
 public class Account  extends AbstractEntity{
 
 	private static final long serialVersionUID = 6174825093869578035L;
 	
+	public static final String TABLENAME = "accounts";
+	
+	public static final String USERNAME = "username";
+	public static final String SERVER = "server";
+	public static final String PASSWORD = "password";
+	
+	protected String username;
+	protected String server;
+	protected String password;
+	
+	protected boolean online = false;
+	
 	public Account() {
-		this.uuid = "";
+		this.uuid = "0";
+	}
+	
+	public Account(String username, String server, String password) {
+		this(java.util.UUID.randomUUID().toString(),username,server,password);
+	}
+	public Account(String uuid, String username, String server,String password) {
+		this.uuid = uuid;
+		this.username = username;
+		this.server = server;
+		this.password = password;
+	}
+	
+	public String getUsername() {
+		return username;
+	}
+
+	public void setUsername(String username) {
+		this.username = username;
+	}
+
+	public String getServer() {
+		return server;
 	}
+
+	public void setServer(String server) {
+		this.server = server;
+	}
+
+	public String getPassword() {
+		return password;
+	}
+
+	public void setPassword(String password) {
+		this.password = password;
+	}
+	
+	public boolean isOnline() {
+		return online;
+	}
+	
+	public String getJid() {
+		return username+"@"+server;
+	}
+
 	@Override
 	public ContentValues getContentValues() {
-		// TODO Auto-generated method stub
-		return null;
+		ContentValues values = new ContentValues();
+		values.put(UUID,uuid);
+		values.put(USERNAME, username);
+		values.put(SERVER, server);
+		values.put(PASSWORD, password);
+		return values;
+	}
+	
+	public static Account fromCursor(Cursor cursor) {
+		return new Account(cursor.getString(cursor.getColumnIndex(UUID)),
+				cursor.getString(cursor.getColumnIndex(USERNAME)),
+				cursor.getString(cursor.getColumnIndex(SERVER)),
+				cursor.getString(cursor.getColumnIndex(PASSWORD)));
 	}
 
 }

src/de/gultsch/chat/entities/Message.java 🔗

@@ -54,7 +54,7 @@ public class Message extends AbstractEntity {
 	@Override
 	public ContentValues getContentValues() {
 		ContentValues values = new ContentValues();
-		values.put(UUID, this.uuid);
+		values.put(UUID, uuid);
 		values.put(CONVERSATION, conversationUuid);
 		values.put(COUNTERPART, counterpart);
 		values.put(BODY, body);

src/de/gultsch/chat/persistance/DatabaseBackend.java 🔗

@@ -11,6 +11,7 @@ import android.content.Context;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteOpenHelper;
+import android.util.Log;
 
 public class DatabaseBackend extends SQLiteOpenHelper {
 
@@ -36,6 +37,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
 				+ Message.COUNTERPART + " TEXT, " + Message.BODY + " TEXT, "
 				+ Message.ENCRYPTION + " NUMBER, " + Message.STATUS
 				+ " NUMBER)");
+		db.execSQL("create table "+Account.TABLENAME+"("+Account.UUID+" TEXT,"+Account.USERNAME+" TEXT,"+Account.SERVER+" TEXT,"+Account.PASSWORD+" TEXT)");
 	}
 
 	@Override
@@ -60,6 +62,11 @@ public class DatabaseBackend extends SQLiteOpenHelper {
 		SQLiteDatabase db = this.getWritableDatabase();
 		db.insert(Message.TABLENAME, null, message.getContentValues());
 	}
+	
+	public void createAccount(Account account) {
+		SQLiteDatabase db = this.getWritableDatabase();
+		db.insert(Account.TABLENAME,null, account.getContentValues());
+	}
 
 	public int getConversationCount() {
 		SQLiteDatabase db = this.getReadableDatabase();
@@ -107,9 +114,33 @@ public class DatabaseBackend extends SQLiteOpenHelper {
 	}
 
 	public void updateConversation(Conversation conversation) {
-		SQLiteDatabase db = this.getReadableDatabase();
+		SQLiteDatabase db = this.getWritableDatabase();
 		String[] args = {conversation.getUuid()};
 		db.update(Conversation.TABLENAME, conversation.getContentValues(),Conversation.UUID+"=?",args);
 	}
+	
+	public List<Account> getAccounts() {
+		List<Account> list = new ArrayList<Account>();
+		SQLiteDatabase db = this.getReadableDatabase();
+		Cursor cursor = db.query(Account.TABLENAME, null, null, null, null, null, null);
+		Log.d("gultsch","found "+cursor.getCount()+" accounts");
+		while (cursor.moveToNext()) {
+			list.add(Account.fromCursor(cursor));
+		}
+		return list;
+	}
+
+	public void updateAccount(Account account) {
+		SQLiteDatabase db = this.getWritableDatabase();
+		String[] args = {account.getUuid()};
+		db.update(Account.TABLENAME, account.getContentValues(),Account.UUID+"=?",args);
+	}
+
+	public void deleteAccount(Account account) {
+		SQLiteDatabase db = this.getWritableDatabase();
+		String[] args = {account.getUuid()};
+		Log.d("gultsch","backend trying to delete account with uuid:"+account.getUuid());
+		db.delete(Account.TABLENAME,Account.UUID+"=?",args);
+	}
 
 }

src/de/gultsch/chat/services/XmppConnectionService.java 🔗

@@ -48,6 +48,10 @@ public class XmppConnectionService extends Service {
     	return databaseBackend.getConversations(status);
     }
     
+    public List<Account> getAccounts() {
+    	return databaseBackend.getAccounts();
+    }
+    
     public List<Message> getMessages(Conversation conversation) {
     	return databaseBackend.getMessages(conversation, 100);
     }
@@ -72,4 +76,16 @@ public class XmppConnectionService extends Service {
     public int getConversationCount() {
     	return this.databaseBackend.getConversationCount();
     }
+
+	public void createAccount(Account account) {
+		databaseBackend.createAccount(account);
+	}
+	
+	public void updateAccount(Account account) {
+		databaseBackend.updateAccount(account);
+	}
+
+	public void deleteAccount(Account account) {
+		databaseBackend.deleteAccount(account);
+	}
 }

src/de/gultsch/chat/ui/ConversationFragment.java 🔗

@@ -154,17 +154,15 @@ public class ConversationFragment extends Fragment {
 			this.conversation = activity.getConversationList().get(activity.getSelectedConversation());
 			this.messageList.clear();
 			this.messageList.addAll(this.conversation.getMessages());
+			// rendering complete. now go tell activity to close pane
+			if (!activity.shouldPaneBeOpen()) {
+				activity.getSlidingPaneLayout().closePane();
+			}
+			
+			int size = this.messageList.size();
+			if (size >= 1)
+				messagesView.setSelection(size - 1);
 		}
-		
-		
-		// rendering complete. now go tell activity to close pane
-		if (!activity.shouldPaneBeOpen()) {
-			activity.getSlidingPaneLayout().closePane();
-		}
-		
-		int size = this.messageList.size();
-		if (size >= 1)
-			messagesView.setSelection(size - 1);
 	}
 	
 	public void onBackendConnected() {
@@ -172,5 +170,9 @@ public class ConversationFragment extends Fragment {
 		this.conversation = activity.getConversationList().get(activity.getSelectedConversation());
 		this.messageList.clear();
 		this.messageList.addAll(this.conversation.getMessages());
+		// rendering complete. now go tell activity to close pane
+		if (!activity.shouldPaneBeOpen()) {
+			activity.getSlidingPaneLayout().closePane();
+		}
 	}
 }

src/de/gultsch/chat/ui/EditAccount.java 🔗

@@ -0,0 +1,196 @@
+package de.gultsch.chat.ui;
+
+import de.gultsch.chat.R;
+import de.gultsch.chat.entities.Account;
+import de.gultsch.chat.utils.Validator;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.EditText;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+public class EditAccount extends DialogFragment {
+
+	protected Account account;
+
+	public void setAccount(Account account) {
+		this.account = account;
+	}
+
+	public interface EditAccountListener {
+		public void onAccountEdited(Account account);
+
+		public void onAccountDelete(Account account);
+	}
+
+	protected EditAccountListener listener = null;
+
+	public void setEditAccountListener(EditAccountListener listener) {
+		this.listener = listener;
+	}
+
+	@Override
+	public Dialog onCreateDialog(Bundle savedInstanceState) {
+		AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+		LayoutInflater inflater = getActivity().getLayoutInflater();
+		View view = inflater.inflate(R.layout.edit_account_dialog, null);
+		final EditText jidText = (EditText) view.findViewById(R.id.account_jid);
+		final EditText usernameText = (EditText) view
+				.findViewById(R.id.account_username);
+		final EditText serverText = (EditText) view
+				.findViewById(R.id.account_server);
+		final TextView usernameDesc = (TextView) view
+				.findViewById(R.id.textView2);
+		final TextView confirmPwDesc = (TextView) view.findViewById(R.id.account_confirm_password_desc);
+		CheckBox showAdvanced = (CheckBox) view
+				.findViewById(R.id.account_show_advanced);
+		final RelativeLayout advancedOptions = (RelativeLayout) view
+				.findViewById(R.id.advanced_options);
+		showAdvanced.setOnCheckedChangeListener(new OnCheckedChangeListener() {
+
+			@Override
+			public void onCheckedChanged(CompoundButton buttonView,
+					boolean isChecked) {
+				if (isChecked) {
+					advancedOptions.setVisibility(View.VISIBLE);
+					usernameDesc.setText("Username");
+					usernameText.setVisibility(View.VISIBLE);
+					jidText.setVisibility(View.GONE);
+				} else {
+					advancedOptions.setVisibility(View.GONE);
+					usernameDesc.setText("Jabber ID");
+					usernameText.setVisibility(View.GONE);
+					jidText.setVisibility(View.VISIBLE);
+				}
+			}
+		});
+
+		final EditText password = (EditText) view
+				.findViewById(R.id.account_password);
+		final EditText passwordConfirm = (EditText) view
+				.findViewById(R.id.account_password_confirm2);
+		final CheckBox registerAccount = (CheckBox) view
+				.findViewById(R.id.edit_account_register_new);
+
+		final String okButtonDesc;
+
+		if (account != null) {
+			builder.setTitle("Edit account");
+			registerAccount.setVisibility(View.GONE);
+			jidText.setText(account.getJid());
+			password.setText(account.getPassword());
+			usernameText.setText(account.getUsername());
+			serverText.setText(account.getServer());
+			okButtonDesc = "Edit";
+			builder.setNegativeButton("Delete Account", new OnClickListener() {
+				
+				@Override
+				public void onClick(DialogInterface dialog, int which) {
+					AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+					builder.setTitle("Are you sure?");
+					builder.setIconAttribute(android.R.attr.alertDialogIcon);
+					builder.setMessage("If you delete your account your entire conversation history will be lost");
+					builder.setPositiveButton("Delete", new OnClickListener() {
+						
+						@Override
+						public void onClick(DialogInterface dialog, int which) {
+							if (listener!=null) {
+								listener.onAccountDelete(account);
+							}
+						}
+					});
+					builder.setNegativeButton("Cancel",null);
+					builder.create().show();
+				}
+			});
+		} else {
+			builder.setTitle("Add account");
+			okButtonDesc = "Add";
+		}
+
+		registerAccount
+				.setOnCheckedChangeListener(new OnCheckedChangeListener() {
+
+					@Override
+					public void onCheckedChanged(CompoundButton buttonView,
+							boolean isChecked) {
+						AlertDialog d = (AlertDialog) getDialog();
+						Button positiveButton = (Button) d.getButton(Dialog.BUTTON_POSITIVE);
+						if (isChecked) {
+							positiveButton.setText("Register");
+							passwordConfirm.setVisibility(View.VISIBLE);
+							confirmPwDesc.setVisibility(View.VISIBLE);
+						} else {
+							passwordConfirm.setVisibility(View.GONE);
+							positiveButton.setText("Add");
+							confirmPwDesc.setVisibility(View.GONE);
+						}
+					}
+				});
+
+		builder.setView(view);
+		builder.setNeutralButton("Cancel", null);
+		builder.setPositiveButton(okButtonDesc, null);
+		return builder.create();
+	}
+
+	@Override
+	public void onStart() {
+		super.onStart();
+		final AlertDialog d = (AlertDialog) getDialog();
+		Button positiveButton = (Button) d.getButton(Dialog.BUTTON_POSITIVE);
+		positiveButton.setOnClickListener(new View.OnClickListener() {
+			@Override
+			public void onClick(View v) {
+				boolean showAdvanced = ((CheckBox) d.findViewById(R.id.account_show_advanced)).isChecked();
+				EditText jidEdit = (EditText) d.findViewById(R.id.account_jid);
+				String jid = jidEdit.getText().toString();
+				EditText usernameEdit = (EditText) d.findViewById(R.id.account_username);
+				String username = usernameEdit.getText().toString();
+				EditText serverEdit = (EditText) d.findViewById(R.id.account_server);
+				String server = serverEdit.getText().toString();
+				EditText passwordEdit = (EditText) d.findViewById(R.id.account_password);
+				String password = passwordEdit.getText().toString();
+				if (!showAdvanced) {
+					if (Validator.isValidJid(jid)) {
+						String[] parts = jid.split("@");
+						username = parts[0];
+						server = parts[1];
+					} else {
+						jidEdit.setError("Invalid Jabber ID");
+						return;
+					}
+				} else {
+					if (username.length()==0) {
+						usernameEdit.setError("username is too short");
+						return;
+					} else if (server.length()==0) {
+						serverEdit.setError("server is too short");
+						return;
+					}
+				}
+				if (account!=null) {
+					account.setPassword(password);
+					account.setUsername(username);
+					account.setServer(server);
+				} else {
+					account = new Account(username, server, password);
+				}
+				if (listener!=null) {
+					listener.onAccountEdited(account);
+					d.dismiss();
+				}
+			}
+		});
+	}
+}

src/de/gultsch/chat/ui/ManageAccountActivity.java 🔗

@@ -1,7 +1,142 @@
 package de.gultsch.chat.ui;
 
-import android.app.Activity;
+import java.util.ArrayList;
+import java.util.List;
 
-public class ManageAccountActivity extends Activity {
+import de.gultsch.chat.R;
+import de.gultsch.chat.entities.Account;
+import de.gultsch.chat.ui.EditAccount.EditAccountListener;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+import android.widget.TextView;
 
+public class ManageAccountActivity extends XmppActivity {
+
+	
+	protected List<Account> accountList = new ArrayList<Account>();
+	protected ListView accountListView;
+	protected ArrayAdapter<Account> accountListViewAdapter;
+	
+	@Override
+	protected void onCreate(Bundle savedInstanceState) {
+
+		super.onCreate(savedInstanceState);
+
+		setContentView(R.layout.manage_accounts);
+		
+		accountListView = (ListView) findViewById(R.id.account_list);
+		accountListViewAdapter = new ArrayAdapter<Account>(getApplicationContext(), R.layout.account_row, this.accountList) {
+			@Override
+			public View getView(int position, View view, ViewGroup parent) {
+				if (view == null) {
+					LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+					view = (View) inflater.inflate(R.layout.account_row, null);
+				}
+					((TextView) view.findViewById(R.id.account_jid)).setText(getItem(position).getJid());
+				
+				return view;
+			}
+		};
+		accountListView.setAdapter(this.accountListViewAdapter);
+		accountListView.setOnItemClickListener(new OnItemClickListener() {
+
+			@Override
+			public void onItemClick(AdapterView<?> arg0, View view, int position,
+					long arg3) {
+				EditAccount dialog = new EditAccount();
+				dialog.setAccount(accountList.get(position));
+				dialog.setEditAccountListener(new EditAccountListener() {
+					
+					@Override
+					public void onAccountEdited(Account account) {
+						xmppConnectionService.updateAccount(account);
+					}
+
+					@Override
+					public void onAccountDelete(Account account) {
+						
+						Log.d("gultsch","deleting account:"+account.getJid());
+						
+						xmppConnectionService.deleteAccount(account);
+						
+						//dont bother finding the right account in the frontend list. just reload
+						accountList.clear();
+						accountList.addAll(xmppConnectionService.getAccounts());
+						
+						accountListViewAdapter.notifyDataSetChanged();
+						
+					}
+				});
+				dialog.show(getFragmentManager(),"edit_account");
+			}
+		});
+	}
+
+	@Override
+	public void onStart() {
+		super.onStart();
+		if (xmppConnectionServiceBound) {
+			Log.d("gultsch","already bound");
+			this.accountList.clear();
+			this.accountList.addAll(xmppConnectionService
+					.getAccounts());
+			accountListViewAdapter.notifyDataSetChanged();
+		}
+	}
+	
+	@Override
+	void onBackendConnected() {
+		Log.d("gultsch","called on backend connected");
+		this.accountList.clear();
+		this.accountList.addAll(xmppConnectionService.getAccounts());
+		accountListViewAdapter.notifyDataSetChanged();
+	}
+	
+	@Override
+	public boolean onCreateOptionsMenu(Menu menu) {
+		// Inflate the menu; this adds items to the action bar if it is present.
+		getMenuInflater().inflate(R.menu.manageaccounts, menu);
+		return true;
+	}
+	
+	@Override
+	public boolean onOptionsItemSelected(MenuItem item) {
+		switch (item.getItemId()) {
+		case R.id.action_settings:
+			startActivity(new Intent(this, SettingsActivity.class));
+			break;
+		case R.id.action_add_account:
+			EditAccount dialog = new EditAccount();
+			dialog.setEditAccountListener(new EditAccountListener() {
+				
+				@Override
+				public void onAccountEdited(Account account) {
+					xmppConnectionService.createAccount(account);
+					accountList.add(account);
+					accountListViewAdapter.notifyDataSetChanged();
+				}
+
+				@Override
+				public void onAccountDelete(Account account) {
+					//this will never be called
+				}
+			});
+			dialog.show(getFragmentManager(),"add_account");
+			break;
+		default:
+			break;
+		}
+		return super.onOptionsItemSelected(item);
+	}
 }

src/de/gultsch/chat/ui/NewConversationActivity.java 🔗

@@ -2,14 +2,13 @@ package de.gultsch.chat.ui;
 
 import java.util.LinkedHashMap;
 import java.util.Map.Entry;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
 import de.gultsch.chat.R;
 import de.gultsch.chat.entities.Account;
 import de.gultsch.chat.entities.Contact;
 import de.gultsch.chat.entities.Conversation;
 import de.gultsch.chat.persistance.DatabaseBackend;
+import de.gultsch.chat.utils.Validator;
 import android.os.Bundle;
 import android.provider.ContactsContract;
 import android.text.Editable;
@@ -36,9 +35,6 @@ public class NewConversationActivity extends XmppActivity {
 	final protected LinkedHashMap<Contact, View> availableJabberContacts = new LinkedHashMap<Contact, View>();
 	protected View newContactView;
 	protected Contact newContact;
-	
-	public static final Pattern VALID_JID = 
-		    Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$", Pattern.CASE_INSENSITIVE);
 
 	static final String[] PROJECTION = new String[] {
 			ContactsContract.Data.CONTACT_ID,
@@ -181,8 +177,7 @@ public class NewConversationActivity extends XmppActivity {
 		}
 		
 		LinearLayout createNewContact = (LinearLayout) findViewById(R.id.create_new_contact);
-		Matcher matcher = VALID_JID.matcher(search);
-		if (matcher.find()) {
+		if (Validator.isValidJid(search)) {
 			createNewContact.removeAllViews();
 			String name = search.split("@")[0];
 			newContact = new Contact(name,search,DEFAULT_PROFILE_PHOTO);
@@ -217,9 +212,10 @@ public class NewConversationActivity extends XmppActivity {
 
 	@Override
 	void onBackendConnected() {
-		
-		getActionBar().setDisplayHomeAsUpEnabled(false);
-		getActionBar().setHomeButtonEnabled(false);
+		if (xmppConnectionService.getConversationCount()==0) {
+			getActionBar().setDisplayHomeAsUpEnabled(false);
+			getActionBar().setHomeButtonEnabled(false);
+		}
 	}
 	
 	@Override

src/de/gultsch/chat/utils/Validator.java 🔗

@@ -0,0 +1,14 @@
+package de.gultsch.chat.utils;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class Validator {
+	public static final Pattern VALID_JID = 
+		    Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$", Pattern.CASE_INSENSITIVE);
+	
+	public static boolean isValidJid(String jid) {
+		Matcher matcher = VALID_JID.matcher(jid);
+		return matcher.find();
+	}
+}