From 665ef7511f5dcccb349228baa2aa6f02281d3c07 Mon Sep 17 00:00:00 2001
From: Daniel Gultsch <daniel.gultsch@rwth-aachen.de>
Date: Sat, 25 Jan 2014 19:33:12 +0100
Subject: [PATCH] all access to the persistance layer is now done via the new
 xmppservice

---
 AndroidManifest.xml                           |   1 +
 gen/de/gultsch/chat/R.java                    |   1 +
 res/menu/newconversation.xml                  |  15 ++
 src/de/gultsch/chat/ConversationCursor.java   |  97 -----------
 src/de/gultsch/chat/ConversationList.java     |  33 ----
 .../gultsch/chat/entities/AbstractEntity.java |  21 +++
 src/de/gultsch/chat/entities/Account.java     |  15 +-
 .../gultsch/chat/entities/Conversation.java   |  67 ++++----
 src/de/gultsch/chat/entities/Message.java     | 101 ++++++++++--
 .../chat/persistance/DatabaseBackend.java     |   9 +-
 .../chat/services/XmppConnectionService.java  |  38 +++--
 .../gultsch/chat/ui/ConversationActivity.java | 153 +++++++++---------
 .../chat/ui/NewConversationActivity.java      |  56 ++++++-
 src/de/gultsch/chat/ui/XmppActivity.java      |  51 ++++++
 14 files changed, 384 insertions(+), 274 deletions(-)
 create mode 100644 res/menu/newconversation.xml
 delete mode 100644 src/de/gultsch/chat/ConversationCursor.java
 delete mode 100644 src/de/gultsch/chat/ConversationList.java
 create mode 100644 src/de/gultsch/chat/entities/AbstractEntity.java
 create mode 100644 src/de/gultsch/chat/ui/XmppActivity.java

diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index e7d5f2c04..be7addb51 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -15,6 +15,7 @@
         android:icon="@drawable/ic_launcher"
         android:label="@string/app_name"
         android:theme="@android:style/Theme.Holo.Light" >
+        <service android:name="de.gultsch.chat.services.XmppConnectionService"/>
         <activity
             android:name="de.gultsch.chat.ui.ConversationActivity"
             android:label="Secure Conversations"
diff --git a/gen/de/gultsch/chat/R.java b/gen/de/gultsch/chat/R.java
index fb44a0af8..0e8cf1af2 100644
--- a/gen/de/gultsch/chat/R.java
+++ b/gen/de/gultsch/chat/R.java
@@ -74,6 +74,7 @@ public final class R {
     }
     public static final class menu {
         public static final int conversations=0x7f090000;
+        public static final int newconversation=0x7f090001;
     }
     public static final class string {
         public static final int action_accounts=0x7f070003;
diff --git a/res/menu/newconversation.xml b/res/menu/newconversation.xml
new file mode 100644
index 000000000..4f9b6da05
--- /dev/null
+++ b/res/menu/newconversation.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item
+        android:id="@+id/action_accounts"
+        android:orderInCategory="90"
+        android:showAsAction="never"
+        android:title="@string/action_accounts"
+	/>
+        
+    <item
+        android:id="@+id/action_settings"
+        android:orderInCategory="100"
+        android:showAsAction="never"
+        android:title="@string/action_settings"/>
+</menu>
diff --git a/src/de/gultsch/chat/ConversationCursor.java b/src/de/gultsch/chat/ConversationCursor.java
deleted file mode 100644
index 5ab3ef563..000000000
--- a/src/de/gultsch/chat/ConversationCursor.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package de.gultsch.chat;
-
-
-import java.util.ArrayList;
-
-import de.gultsch.chat.entities.Conversation;
-import de.gultsch.chat.entities.Message;
-
-
-import android.database.AbstractCursor;
-
-public class ConversationCursor extends AbstractCursor {
-
-	
-	protected ConversationList conversations;
-	
-	public static final String NAME = "conversationname";
-	public static final String LAST_MSG = "lastmsg";
-	public static final String DATE = "date";
-	public static final String ID = "_id";
-	
-	public ConversationCursor(ConversationList list) {
-		super();
-		this.conversations = list;
-	}
-	
-	public ArrayList<Conversation> getConversationOverview() {
-		return this.conversations;
-	}
-	
-	public void setConversationOverview(ConversationList list) {
-		this.conversations = list;
-	}
-	
-	@Override
-	public String[] getColumnNames() {
-		return new String[]{ID,NAME,LAST_MSG,DATE};
-	}
-
-	@Override
-	public int getCount() {
-		return conversations.size();
-	}
-
-	@Override
-	public double getDouble(int column) {
-		// TODO Auto-generated method stub
-		return 0;
-	}
-
-	@Override
-	public float getFloat(int column) {
-		// TODO Auto-generated method stub
-		return 0;
-	}
-
-	@Override
-	public int getInt(int column) {
-		// TODO Auto-generated method stub
-		return 0;
-	}
-
-	@Override
-	public long getLong(int column) {
-		// TODO Auto-generated method stub
-		return 0;
-	}
-
-	@Override
-	public short getShort(int column) {
-		// TODO Auto-generated method stub
-		return 0;
-	}
-
-	@Override
-	public String getString(int column) {
-		Conversation conversation = conversations.get(getPosition());
-		Message lastMessage = conversation.getLastMessages(1,0).get(0);
-		switch (column) {
-		case 1:
-			return conversation.getName();
-		case 2:
-			return lastMessage.toString();
-		case 3:
-			return lastMessage.getTimeReadable();
-		default:
-			return null;
-		}
-	}
-
-	@Override
-	public boolean isNull(int column) {
-		// TODO Auto-generated method stub
-		return false;
-	}
-	
-}
\ No newline at end of file
diff --git a/src/de/gultsch/chat/ConversationList.java b/src/de/gultsch/chat/ConversationList.java
deleted file mode 100644
index ac5f92301..000000000
--- a/src/de/gultsch/chat/ConversationList.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package de.gultsch.chat;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-
-import de.gultsch.chat.entities.Conversation;
-
-public class ConversationList extends ArrayList<Conversation> {
-	
-	private static final long serialVersionUID = 3661496589984289968L;
-	
-	private int selectedConversationPosition = -1;
-	
-	private ConversationCursor cursor = new ConversationCursor(this);
-
-	public ConversationCursor getCursor() {
-		return this.cursor;
-	}
-
-	public Conversation getSelectedConversation() {
-		return this.get(this.selectedConversationPosition);
-	}
-
-	public void setSelectedConversationPosition(int selectedConversation) {
-		this.selectedConversationPosition = selectedConversation;
-	}
-	
-	public synchronized int addAndReturnPosition(Conversation conversation) {
-		this.add(conversation);
-		return size() - 1;
-	}
-}
diff --git a/src/de/gultsch/chat/entities/AbstractEntity.java b/src/de/gultsch/chat/entities/AbstractEntity.java
new file mode 100644
index 000000000..d62385a6a
--- /dev/null
+++ b/src/de/gultsch/chat/entities/AbstractEntity.java
@@ -0,0 +1,21 @@
+package de.gultsch.chat.entities;
+
+import java.io.Serializable;
+
+import android.content.ContentValues;
+
+public abstract class AbstractEntity implements Serializable {
+
+	private static final long serialVersionUID = -1895605706690653719L;
+	
+	public static final String UUID = "uuid";
+	
+	protected String uuid;
+	
+	public String getUuid() {
+		return this.uuid;
+	}
+	
+	public abstract ContentValues getContentValues();
+	
+}
diff --git a/src/de/gultsch/chat/entities/Account.java b/src/de/gultsch/chat/entities/Account.java
index f1e15f0b3..5b83ca799 100644
--- a/src/de/gultsch/chat/entities/Account.java
+++ b/src/de/gultsch/chat/entities/Account.java
@@ -1,11 +1,18 @@
 package de.gultsch.chat.entities;
 
-public class Account {
+import android.content.ContentValues;
 
-	private String uuid;
+public class Account  extends AbstractEntity{
 
-	public String getUuid() {
-		return this.uuid;
+	private static final long serialVersionUID = 6174825093869578035L;
+	
+	public Account() {
+		this.uuid = "";
+	}
+	@Override
+	public ContentValues getContentValues() {
+		// TODO Auto-generated method stub
+		return null;
 	}
 
 }
diff --git a/src/de/gultsch/chat/entities/Conversation.java b/src/de/gultsch/chat/entities/Conversation.java
index 92d5bcba6..2dd8a0495 100644
--- a/src/de/gultsch/chat/entities/Conversation.java
+++ b/src/de/gultsch/chat/entities/Conversation.java
@@ -1,58 +1,64 @@
 package de.gultsch.chat.entities;
 
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.UUID;
+import java.util.List;
 
 import android.content.ContentValues;
 import android.database.Cursor;
 import android.net.Uri;
 
-public class Conversation implements Serializable {
+public class Conversation extends AbstractEntity {
 
 	private static final long serialVersionUID = -6727528868973996739L;
 	public static final int STATUS_AVAILABLE = 0;
 	public static final int STATUS_ARCHIVED = 1;
 	public static final int STATUS_DELETED = 2;
-	private String uuid;
+
+	public static final String NAME = "name";
+	public static final String PHOTO_URI = "profilePhotoUri";
+	public static final String ACCOUNT = "accountUuid";
+	public static final String CONTACT = "contactJid";
+	public static final String STATUS = "status";
+	public static final String CREATED = "created";
+
 	private String name;
 	private String profilePhotoUri;
 	private String accountUuid;
 	private String contactJid;
 	private int status;
+	private long created;
 
-	// legacy. to be removed
-	private ArrayList<Message> msgs = new ArrayList<Message>();
+	private transient List<Message> messages;
 
 	public Conversation(String name, Uri profilePhoto, Account account,
 			String contactJid) {
-		this(UUID.randomUUID().toString(), name, profilePhoto.toString(),
-				account.getUuid(), contactJid, STATUS_AVAILABLE);
+		this(java.util.UUID.randomUUID().toString(), name, profilePhoto
+				.toString(), account.getUuid(), contactJid, System
+				.currentTimeMillis(), STATUS_AVAILABLE);
 	}
 
 	public Conversation(String uuid, String name, String profilePhoto,
-			String accountUuid, String contactJid, int status) {
+			String accountUuid, String contactJid, long created, int status) {
 		this.uuid = uuid;
 		this.name = name;
 		this.profilePhotoUri = profilePhoto;
 		this.accountUuid = accountUuid;
 		this.contactJid = contactJid;
+		this.created = created;
 		this.status = status;
 	}
 
-	public ArrayList<Message> getLastMessages(int count, int offset) {
-		msgs.add(new Message("this is my last message"));
-		return msgs;
+	public List<Message> getMessages() {
+		return messages;
+	}
+
+	public void setMessages(List<Message> msgs) {
+		this.messages = msgs;
 	}
 
 	public String getName() {
 		return this.name;
 	}
 
-	public String getUuid() {
-		return this.uuid;
-	}
-
 	public String getProfilePhotoString() {
 		return this.profilePhotoUri;
 	}
@@ -78,22 +84,23 @@ public class Conversation implements Serializable {
 
 	public ContentValues getContentValues() {
 		ContentValues values = new ContentValues();
-		values.put("uuid", this.uuid);
-		values.put("name", this.name);
-		values.put("profilePhotoUri", this.profilePhotoUri);
-		values.put("accountUuid", this.accountUuid);
-		values.put("contactJid", this.contactJid);
-		values.put("status", this.status);
+		values.put(UUID, uuid);
+		values.put(NAME, name);
+		values.put(PHOTO_URI, profilePhotoUri);
+		values.put(ACCOUNT, accountUuid);
+		values.put(CONTACT, contactJid);
+		values.put(CREATED, created);
+		values.put(STATUS, status);
 		return values;
 	}
 
 	public static Conversation fromCursor(Cursor cursor) {
-		return new Conversation(
-				cursor.getString(cursor.getColumnIndex("uuid")),
-				cursor.getString(cursor.getColumnIndex("name")),
-				cursor.getString(cursor.getColumnIndex("profilePhotoUri")),
-				cursor.getString(cursor.getColumnIndex("accountUuid")),
-				cursor.getString(cursor.getColumnIndex("contactJid")),
-				cursor.getInt(cursor.getColumnIndex("status")));
+		return new Conversation(cursor.getString(cursor.getColumnIndex(UUID)),
+				cursor.getString(cursor.getColumnIndex(NAME)),
+				cursor.getString(cursor.getColumnIndex(PHOTO_URI)),
+				cursor.getString(cursor.getColumnIndex(ACCOUNT)),
+				cursor.getString(cursor.getColumnIndex(CONTACT)),
+				cursor.getLong(cursor.getColumnIndex(CREATED)),
+				cursor.getInt(cursor.getColumnIndex(STATUS)));
 	}
 }
diff --git a/src/de/gultsch/chat/entities/Message.java b/src/de/gultsch/chat/entities/Message.java
index 3b4e21150..5e5cfbe40 100644
--- a/src/de/gultsch/chat/entities/Message.java
+++ b/src/de/gultsch/chat/entities/Message.java
@@ -1,19 +1,98 @@
 package de.gultsch.chat.entities;
 
-public class Message {
+import android.content.ContentValues;
+import android.database.Cursor;
 
-	String msg;
-	
-	public Message(String msg) {
-		this.msg = msg;
-	}
-	
-	public String toString() {
-		return msg;
+public class Message extends AbstractEntity {
+
+	private static final long serialVersionUID = 7222081895167103025L;
+
+	public static final int STATUS_RECIEVED = 0;
+	public static final int STATUS_UNSEND = 1;
+	public static final int STATUS_SEND = 2;
+
+	public static final int ENCRYPTION_NONE = 0;
+	public static final int ENCRYPTION_PGP = 1;
+	public static final int ENCRYPTION_OTR = 2;
+
+	public static String CONVERSATION = "conversationUuid";
+	public static String COUNTERPART = "counterpart";
+	public static String BODY = "body";
+	public static String TIME_SENT = "timeSent";
+	public static String ENCRYPTION = "encryption";
+	public static String STATUS = "status";
+
+	protected String conversationUuid;
+	protected String counterpart;
+	protected String body;
+	protected long timeSent;
+	protected int encryption;
+	protected int status;
+
+	protected transient Conversation conversation = null;
+
+	public Message(Conversation conversation, String body, int encryption) {
+		this(java.util.UUID.randomUUID().toString(), conversation.getUuid(),
+				conversation.getContactJid(), body, 0, encryption,
+				Message.STATUS_UNSEND);
 	}
 
-	public String getTimeReadable() {
-		return "2 min";
+	public Message(String uuid, String conversationUUid, String counterpart,
+			String body, long timeSent, int encryption, int status) {
+		this.uuid = uuid;
+		this.conversationUuid = conversationUUid;
+		this.counterpart = counterpart;
+		this.body = body;
+		this.timeSent = timeSent;
+		this.encryption = encryption;
+		this.status = status;
+	}
+
+	@Override
+	public ContentValues getContentValues() {
+		ContentValues values = new ContentValues();
+		values.put(UUID, this.uuid);
+		values.put(CONVERSATION, conversationUuid);
+		values.put(COUNTERPART, counterpart);
+		values.put(BODY, body);
+		values.put(TIME_SENT, timeSent);
+		values.put(ENCRYPTION, encryption);
+		values.put(STATUS, status);
+		return values;
+	}
+
+	public String getConversationUuid() {
+		return conversationUuid;
+	}
+
+	public String getCounterpart() {
+		return counterpart;
+	}
+
+	public String getBody() {
+		return body;
+	}
+
+	public long getTimeSent() {
+		return timeSent;
+	}
+
+	public int getEncryption() {
+		return encryption;
+	}
+
+	public int getStatus() {
+		return status;
+	}
+
+	public static Message fromCursor(Cursor cursor) {
+		return new Message(cursor.getString(cursor.getColumnIndex(UUID)),
+				cursor.getString(cursor.getColumnIndex(CONVERSATION)),
+				cursor.getString(cursor.getColumnIndex(COUNTERPART)),
+				cursor.getString(cursor.getColumnIndex(BODY)),
+				cursor.getLong(cursor.getColumnIndex(TIME_SENT)),
+				cursor.getInt(cursor.getColumnIndex(ENCRYPTION)),
+				cursor.getInt(cursor.getColumnIndex(STATUS)));
 	}
 
 }
diff --git a/src/de/gultsch/chat/persistance/DatabaseBackend.java b/src/de/gultsch/chat/persistance/DatabaseBackend.java
index 5ce7f7e03..dac83f586 100644
--- a/src/de/gultsch/chat/persistance/DatabaseBackend.java
+++ b/src/de/gultsch/chat/persistance/DatabaseBackend.java
@@ -8,7 +8,6 @@ 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 {
 	
@@ -23,7 +22,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
 
 	@Override
 	public void onCreate(SQLiteDatabase db) {
-		db.execSQL("create table conversations (uuid TEXT, name TEXT, profilePhotoUri TEXT, accountUuid TEXT, contactJid TEXT)");
+		db.execSQL("create table conversations (uuid TEXT, name TEXT, profilePhotoUri TEXT, accountUuid TEXT, contactJid TEXT, created NUMBER, status NUMBER)");
 	}
 
 	@Override
@@ -34,7 +33,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
 	
 	public static synchronized DatabaseBackend getInstance(Context context) {
 		if (instance == null) {
-			instance = new DatabaseBackend(context.getApplicationContext());
+			instance = new DatabaseBackend(context);
 		}
 		return instance;
 	}
@@ -56,10 +55,8 @@ public class DatabaseBackend extends SQLiteOpenHelper {
 		List<Conversation> list = new ArrayList<Conversation>();
 		SQLiteDatabase db = this.getReadableDatabase();
 		String[] selectionArgs = {""+status};
-		Cursor cursor = db.rawQuery("select * from conversations where status = ?", selectionArgs);
-		Log.d("gultsch","getConversations has found "+cursor.getCount()+" rows");
+		Cursor cursor = db.rawQuery("select * from conversations where status = ? order by created desc", selectionArgs);
 		while(cursor.moveToNext()) {
-			Log.d("gultsch","converting row #"+cursor.getPosition());
 			list.add(Conversation.fromCursor(cursor));
 		}
 		return list;
diff --git a/src/de/gultsch/chat/services/XmppConnectionService.java b/src/de/gultsch/chat/services/XmppConnectionService.java
index 4477513d3..67e3901e7 100644
--- a/src/de/gultsch/chat/services/XmppConnectionService.java
+++ b/src/de/gultsch/chat/services/XmppConnectionService.java
@@ -1,29 +1,49 @@
 package de.gultsch.chat.services;
 
+import java.util.List;
+
+import de.gultsch.chat.entities.Conversation;
+import de.gultsch.chat.entities.Message;
+import de.gultsch.chat.persistance.DatabaseBackend;
 import android.app.Service;
 import android.content.Intent;
 import android.os.Binder;
 import android.os.IBinder;
+import android.util.Log;
 
 public class XmppConnectionService extends Service {
+	
+	protected static final String LOGTAG = "xmppConnection";
+	protected DatabaseBackend databaseBackend;
 
-	// Binder given to clients
     private final IBinder mBinder = new XmppConnectionBinder();
 
-    /**
-     * Class used for the client Binder.  Because we know this service always
-     * runs in the same process as its clients, we don't need to deal with IPC.
-     */
     public class XmppConnectionBinder extends Binder {
-        XmppConnectionService getService() {
-            // Return this instance of LocalService so clients can call public methods
-            return XmppConnectionService.this;
+        public XmppConnectionService getService() {
+        	return XmppConnectionService.this;
         }
     }
-
+    
+    @Override
+    public void onCreate() {
+    	databaseBackend = DatabaseBackend.getInstance(getApplicationContext());
+    }
+    
     @Override
     public IBinder onBind(Intent intent) {
         return mBinder;
     }
+    
+    public void sendMessage(Message message) {
+    	Log.d(LOGTAG,"sending message");
+    }
+    
+    public void addConversation(Conversation conversation) {
+    	databaseBackend.addConversation(conversation);
+    }
+    
+    public List<Conversation> getConversations(int status) {
+    	return databaseBackend.getConversations(status);
+    }
 
 }
diff --git a/src/de/gultsch/chat/ui/ConversationActivity.java b/src/de/gultsch/chat/ui/ConversationActivity.java
index f26d89821..97b937c35 100644
--- a/src/de/gultsch/chat/ui/ConversationActivity.java
+++ b/src/de/gultsch/chat/ui/ConversationActivity.java
@@ -1,20 +1,15 @@
 package de.gultsch.chat.ui;
 
-import java.util.HashMap;
+import java.util.ArrayList;
 import java.util.List;
 
-import de.gultsch.chat.ConversationCursor;
-import de.gultsch.chat.ConversationList;
 import de.gultsch.chat.R;
 import de.gultsch.chat.R.id;
 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 android.net.Uri;
 import android.os.Bundle;
-import android.app.Activity;
-import android.app.FragmentManager;
 import android.app.FragmentTransaction;
 import android.content.Context;
 import android.content.Intent;
@@ -35,59 +30,52 @@ import android.widget.ListView;
 import android.widget.TextView;
 import android.widget.ImageView;
 
-public class ConversationActivity extends Activity {
+public class ConversationActivity extends XmppActivity {
 
-	public static final String START_CONVERSATION = "startconversation";
-	public static final String CONVERSATION_CONTACT = "conversationcontact";
+	public static final String VIEW_CONVERSATION = "viewConversation";
+	private static final String LOGTAG = "secureconversation";
+	protected static final String CONVERSATION = "conversationUuid";
 
 	protected SlidingPaneLayout spl;
 
-	protected HashMap<Conversation, ConversationFragment> conversationFragments = new HashMap<Conversation, ConversationFragment>();
-	private DatabaseBackend dbb;
+	final List<Conversation> conversationList = new ArrayList<Conversation>();
 
 	@Override
 	protected void onCreate(Bundle savedInstanceState) {
-		
-		dbb = DatabaseBackend.getInstance(this);
-		
+
 		super.onCreate(savedInstanceState);
 
-		final List<Conversation> conversationList = dbb.getConversations(Conversation.STATUS_AVAILABLE);
-
-		if (getIntent().getAction().equals(Intent.ACTION_MAIN)) {
-			if (conversationList.size() < 0) {
-				Log.d("gultsch",
-						"no conversations detected. redirect to new conversation activity");
-				startActivity(new Intent(this, NewConversationActivity.class));
-				finish();
-			}
-		}
-
 		setContentView(R.layout.fragment_conversations_overview);
 
 		final ListView listView = (ListView) findViewById(R.id.list);
-		
-		listView.setAdapter(new ArrayAdapter<Conversation>(this, R.layout.conversation_list_row, conversationList) {
+
+		listView.setAdapter(new ArrayAdapter<Conversation>(this,
+				R.layout.conversation_list_row, conversationList) {
 			@Override
-			public View getView (int position, View view, ViewGroup parent) {
+			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.conversation_list_row,null);
-					((TextView) view.findViewById(R.id.conversation_name)).setText(getItem(position).getName());
-					((ImageView) view.findViewById(R.id.conversation_image)).setImageURI(getItem(position).getProfilePhotoUri());
+					LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+					view = (View) inflater.inflate(
+							R.layout.conversation_list_row, null);
 				}
+				((TextView) view.findViewById(R.id.conversation_name))
+						.setText(getItem(position).getName());
+				((ImageView) view.findViewById(R.id.conversation_image))
+						.setImageURI(getItem(position).getProfilePhotoUri());
 				return view;
 			}
-			
+
 		});
-		
+
 		listView.setOnItemClickListener(new OnItemClickListener() {
 
 			@Override
 			public void onItemClick(AdapterView<?> arg0, View clickedView,
 					int position, long arg3) {
+				Log.d(LOGTAG, "List view was klicked on position " + position);
 				swapConversationFragment(conversationList.get(position));
-				getActionBar().setTitle(conversationList.get(position).getName());
+				getActionBar().setTitle(
+						conversationList.get(position).getName());
 				spl.closePane();
 			}
 		});
@@ -121,8 +109,14 @@ public class ConversationActivity extends Activity {
 			public void onPanelClosed(View arg0) {
 				if (conversationList.size() > 0) {
 					getActionBar().setDisplayHomeAsUpEnabled(true);
-					ConversationFragment convFrag = (ConversationFragment) getFragmentManager().findFragmentById(R.id.selected_conversation);
-					getActionBar().setTitle(convFrag.getConversation().getName());
+					ConversationFragment convFrag = (ConversationFragment) getFragmentManager()
+							.findFragmentById(R.id.selected_conversation);
+					if (convFrag == null) {
+						Log.d(LOGTAG, "conversation fragment was not found.");
+						return; // just do nothing. at least dont crash
+					}
+					getActionBar().setTitle(
+							convFrag.getConversation().getName());
 					invalidateOptionsMenu();
 				}
 			}
@@ -133,36 +127,6 @@ public class ConversationActivity extends Activity {
 
 			}
 		});
-
-		if (getIntent().getAction().equals(Intent.ACTION_VIEW)) {
-			if (getIntent().getType().equals(
-					ConversationActivity.START_CONVERSATION)) {
-				Contact contact = (Contact) getIntent().getExtras().get(
-						ConversationActivity.CONVERSATION_CONTACT);
-				Log.d("gultsch",
-						"start conversation with " + contact.getDisplayName());
-
-				// start new conversation
-				Conversation conversation = new Conversation(
-						contact.getDisplayName(), contact.getProfilePhoto(),
-						new Account(), contact.getJid());
-
-				//@TODO don't write to database here; always go through service
-				dbb.addConversation(conversation);
-				conversationList.add(0, conversation);
-				swapConversationFragment(conversationList.get(0));
-				spl.closePane();
-
-				// why do i even need this
-				getActionBar().setDisplayHomeAsUpEnabled(true);
-				getActionBar().setTitle(conversationList.get(0).getName());
-			}
-		} else {
-			// normal startup
-			if (conversationList.size() >= 1) {
-				swapConversationFragment(conversationList.get(0));
-			}
-		}
 	}
 
 	@Override
@@ -195,7 +159,8 @@ public class ConversationActivity extends Activity {
 		case R.id.action_add:
 			startActivity(new Intent(this, NewConversationActivity.class));
 		case R.id.action_archive:
-			
+
+			break;
 		default:
 			break;
 		}
@@ -203,14 +168,9 @@ public class ConversationActivity extends Activity {
 	}
 
 	protected void swapConversationFragment(Conversation conv) {
-		ConversationFragment selectedFragment;
-		if (conversationFragments.containsKey(conv)) {
-			selectedFragment = conversationFragments.get(conv);
-		} else {
-			selectedFragment = new ConversationFragment();
-			selectedFragment.setConversation(conv);
-			conversationFragments.put(conv,selectedFragment);
-		}
+		Log.d(LOGTAG, "swap conversation fragment to " + conv.getName());
+		ConversationFragment selectedFragment = new ConversationFragment();
+		selectedFragment.setConversation(conv);
 		FragmentTransaction transaction = getFragmentManager()
 				.beginTransaction();
 		transaction.replace(R.id.selected_conversation, selectedFragment);
@@ -228,4 +188,45 @@ public class ConversationActivity extends Activity {
 		return super.onKeyDown(keyCode, event);
 	}
 
+	@Override
+	public void onStart() {
+		super.onStart();
+		if (xmppConnectionServiceBound) {
+			conversationList.clear();
+			conversationList.addAll(xmppConnectionService
+					.getConversations(Conversation.STATUS_AVAILABLE));
+		}
+	}
+
+	@Override
+	void servConnected() {
+		conversationList.clear();
+		conversationList.addAll(xmppConnectionService
+				.getConversations(Conversation.STATUS_AVAILABLE));
+
+		//spl.openPane();
+
+		if ((getIntent().getAction().equals(Intent.ACTION_VIEW) && (!handledViewIntent))) {
+			if (getIntent().getType().equals(
+					ConversationActivity.VIEW_CONVERSATION)) {
+				handledViewIntent = true;
+
+				swapConversationFragment(conversationList.get(0));
+				spl.closePane();
+
+				// why do i even need this
+				getActionBar().setDisplayHomeAsUpEnabled(true);
+				getActionBar().setTitle(conversationList.get(0).getName());
+
+			}
+		} else {
+			if (conversationList.size() <= 0) {
+				//add no history
+				startActivity(new Intent(this, NewConversationActivity.class));
+				finish();
+			} else {
+				swapConversationFragment(conversationList.get(0));
+			}
+		}
+	}
 }
diff --git a/src/de/gultsch/chat/ui/NewConversationActivity.java b/src/de/gultsch/chat/ui/NewConversationActivity.java
index 9dc385a42..917b4c627 100644
--- a/src/de/gultsch/chat/ui/NewConversationActivity.java
+++ b/src/de/gultsch/chat/ui/NewConversationActivity.java
@@ -6,7 +6,9 @@ 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 android.os.Bundle;
 import android.provider.ContactsContract;
@@ -14,12 +16,13 @@ import android.text.Editable;
 import android.text.TextWatcher;
 import android.util.Log;
 import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 import android.widget.ImageView;
-import android.app.Activity;
 import android.content.Context;
 import android.content.CursorLoader;
 import android.content.Intent;
@@ -27,7 +30,7 @@ import android.content.Loader;
 import android.content.Loader.OnLoadCompleteListener;
 import android.database.Cursor;
 
-public class NewConversationActivity extends Activity {
+public class NewConversationActivity extends XmppActivity {
 
 	final protected LinkedHashMap<Contact, View> availablePhoneContacts = new LinkedHashMap<Contact, View>();
 	final protected LinkedHashMap<Contact, View> availableJabberContacts = new LinkedHashMap<Contact, View>();
@@ -78,12 +81,20 @@ public class NewConversationActivity extends Activity {
 					clickedContact = newContact;
 				}
 				Log.d("gultsch","clicked on "+clickedContact.getDisplayName());
-				Intent startConversationIntent = new Intent(v.getContext(),ConversationActivity.class);
-				startConversationIntent.setAction(Intent.ACTION_VIEW);
-				startConversationIntent.putExtra(ConversationActivity.CONVERSATION_CONTACT, clickedContact);
-				startConversationIntent.setType(ConversationActivity.START_CONVERSATION);
-				startConversationIntent.setFlags(startConversationIntent.getFlags() | Intent.FLAG_ACTIVITY_CLEAR_TOP);
-				startActivity(startConversationIntent);
+				
+				
+				Account account = new Account();
+				
+				Conversation conversation = new Conversation(clickedContact.getDisplayName(), clickedContact.getProfilePhoto(), account, clickedContact.getJid());
+			
+				xmppConnectionService.addConversation(conversation);
+				
+				Intent viewConversationIntent = new Intent(v.getContext(),ConversationActivity.class);
+				viewConversationIntent.setAction(Intent.ACTION_VIEW);
+				viewConversationIntent.putExtra(ConversationActivity.CONVERSATION, conversation.getUuid());
+				viewConversationIntent.setType(ConversationActivity.VIEW_CONVERSATION);
+				viewConversationIntent.setFlags(viewConversationIntent.getFlags() | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+				startActivity(viewConversationIntent);
 			}
 		});
 		return view;
@@ -205,4 +216,33 @@ public class NewConversationActivity extends Activity {
 			lastContact.findViewById(R.id.contact_divider).setVisibility(View.GONE);
 		}
 	}
+
+	@Override
+	void servConnected() {
+		// TODO Auto-generated method stub
+		
+	}
+	
+	@Override
+	public boolean onCreateOptionsMenu(Menu menu) {
+		// Inflate the menu; this adds items to the action bar if it is present.
+		getMenuInflater().inflate(R.menu.newconversation, 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_accounts:
+			startActivity(new Intent(this, ManageAccountActivity.class));
+			break;
+		default:
+			break;
+		}
+		return super.onOptionsItemSelected(item);
+	}
+	
 }
diff --git a/src/de/gultsch/chat/ui/XmppActivity.java b/src/de/gultsch/chat/ui/XmppActivity.java
new file mode 100644
index 000000000..991730413
--- /dev/null
+++ b/src/de/gultsch/chat/ui/XmppActivity.java
@@ -0,0 +1,51 @@
+package de.gultsch.chat.ui;
+
+import de.gultsch.chat.services.XmppConnectionService;
+import de.gultsch.chat.services.XmppConnectionService.XmppConnectionBinder;
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+
+public abstract class XmppActivity extends Activity {
+	protected XmppConnectionService xmppConnectionService;
+	protected boolean xmppConnectionServiceBound = false;
+	protected boolean handledViewIntent = false;
+	protected ServiceConnection mConnection = new ServiceConnection() {
+
+		@Override
+		public void onServiceConnected(ComponentName className, IBinder service) {
+			XmppConnectionBinder binder = (XmppConnectionBinder) service;
+			xmppConnectionService = binder.getService();
+			xmppConnectionServiceBound = true;
+			servConnected();
+		}
+
+		@Override
+		public void onServiceDisconnected(ComponentName arg0) {
+			xmppConnectionServiceBound = false;
+		}
+	};
+	
+	@Override
+	protected void onStart() {
+		super.onStart();
+		if (!xmppConnectionServiceBound) {
+			Intent intent = new Intent(this, XmppConnectionService.class);
+			bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
+		}
+	}
+	
+	@Override
+	protected void onStop() {
+		super.onStop();
+		if (xmppConnectionServiceBound) {
+			unbindService(mConnection);
+			xmppConnectionServiceBound = false;
+		}
+	}
+	
+	abstract void servConnected();
+}