merge avec marseille
authorDa Risk <darisk972@gmail.com>
Wed, 01 Apr 2009 19:24:05 +0200
changeset 48 e7a787b81100
parent 47 743ccc7961dc (diff)
parent 43 4e7c6918b092 (current diff)
child 49 b6d4f4af9e4c
merge avec marseille
res/layout/contactlist.xml
src/com/beem/project/beem/ui/ContactList.java
--- a/res/layout/contactlist.xml	Fri Mar 27 18:12:43 2009 +0100
+++ b/res/layout/contactlist.xml	Wed Apr 01 19:24:05 2009 +0200
@@ -1,24 +1,16 @@
 <?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- 	android:layout_width="fill_parent"
-    android:layout_height="wrap_content"
-    android:orientation="vertical">
-                    	         	
-	<ImageView android:id="@+id/avatar"
-		android:src="@drawable/avatar"
-		android:paddingLeft="50sp"
-		android:layout_width="wrap_content"
-		android:layout_height="wrap_content"/>
- 
-     <TextView android:id="@+id/textchild1"
-         android:textSize="16sp"         
-         android:paddingLeft="100sp"
-         android:layout_width="fill_parent"
-         android:layout_height="wrap_content"/>
-         
-	<TextView android:id="@+id/textchild2"
-         android:textSize="16sp"         
-         android:paddingLeft="100sp"
-         android:layout_width="fill_parent"
-         android:layout_height="wrap_content"/>
- </LinearLayout>
+        android:orientation="vertical"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent">
+
+        <ExpandableListView android:id="@+id/android:list"
+			android:layout_width="fill_parent"
+			android:layout_height="fill_parent"
+            android:layout_weight="1" />
+
+        <TextView android:id="@+id/android:empty"
+			android:layout_width="fill_parent"
+            android:layout_height="fill_parent" android:text="Non connecte" />
+
+</LinearLayout>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/res/layout/contactlistcontact.xml	Wed Apr 01 19:24:05 2009 +0200
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:orientation="horizontal"
+        android:layout_width="fill_parent"
+        android:layout_height="50sp" 
+        android:gravity="center_vertical" >
+
+        <ImageView android:id="@+id/avatar"
+        	android:layout_width="70px"
+            android:layout_height="40sp" />
+		<LinearLayout
+			android:orientation="vertical"
+        	android:layout_width="fill_parent"
+        	android:layout_height="40sp">
+        		
+        	<TextView android:id="@+id/textchild1"
+				android:layout_width="fill_parent"
+            	android:layout_height="wrap_content"
+            	android:paddingLeft="20sp" />
+
+        	<TextView android:id="@+id/textchild2"
+				android:layout_width="fill_parent"
+            	android:layout_height="wrap_content" />
+		</LinearLayout>
+
+</LinearLayout> 
\ No newline at end of file
--- a/res/layout/contactlistgroup.xml	Fri Mar 27 18:12:43 2009 +0100
+++ b/res/layout/contactlistgroup.xml	Wed Apr 01 19:24:05 2009 +0200
@@ -1,16 +1,18 @@
 <?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-	android:layout_width="fill_parent"
-    android:layout_height="wrap_content"
-    android:orientation="vertical">
+        android:orientation="horizontal"
+        android:layout_width="fill_parent"
+        android:layout_height="50sp"
+		android:paddingTop="5sp"
+		android:gravity="center_vertical">
 
-	<TextView android:id="@+id/textgroup"
-		android:height="50sp"
-		android:textSize="20sp"
-       	android:textStyle="bold"
-       	android:paddingTop="10sp"
-       	android:paddingLeft="40sp"
-       	android:layout_width="fill_parent"
-       	android:layout_height="wrap_content" />	
+        <TextView android:id="@+id/textgroup"
+        	android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:paddingLeft="40sp" />
 
- </LinearLayout>
+        <TextView android:id="@+id/rowText2"
+			android:layout_width="fill_parent"
+            android:layout_height="wrap_content" />
+
+</LinearLayout> 
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/beem/project/beem/BeemApplication.java	Wed Apr 01 19:24:05 2009 +0200
@@ -0,0 +1,124 @@
+/**
+ * 
+ */
+package com.beem.project.beem;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import android.app.Activity;
+import android.app.Application;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+
+import com.beem.project.beem.service.aidl.IXMPPFacade;
+
+/**
+ * @author darisk
+ */
+public class BeemApplication extends Application {
+
+    private IXMPPFacade mFacade;
+  
+    private Context mApplicationContext;
+    private Resources mPrivateResources;
+    private static BeemApplication mBeemApp;
+    private List<Message> mQueue = new LinkedList<Message>();
+    private boolean mIsConnected;
+    
+    public static BeemApplication getApplication(Activity activity) {
+	if (mBeemApp == null) {
+	    mBeemApp = new BeemApplication();
+	    mBeemApp.mApplicationContext = activity.getApplication();
+	    mBeemApp.mPrivateResources = activity.getResources();
+	    mBeemApp.onCreate();
+	}
+	return mBeemApp;
+    }
+    
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+	// TODO Auto-generated method stub
+	super.onConfigurationChanged(newConfig);
+    }
+
+    @Override
+    public void onCreate() {
+	// TODO Auto-generated method stub
+	super.onCreate();
+	mFacade = null;
+    }
+
+    @Override
+    public void onLowMemory() {
+	// TODO Auto-generated method stub
+	super.onLowMemory();
+    }
+
+    @Override
+    public void onTerminate() {
+	// TODO Auto-generated method stub
+	super.onTerminate();
+    }
+
+    public synchronized void startBeemService() {
+	if (!mIsConnected) {
+	    // Intent intent = new Intent(this, BeemService.class);
+	    Intent intent = new Intent();
+	    intent.setComponent(new ComponentName("com.beem.project.beem", "com.beem.project.beem.BeemService"));
+	    mApplicationContext.startService(intent);
+	    mApplicationContext.bindService(intent, mServConn, BIND_AUTO_CREATE);
+	    mIsConnected = true;
+	}
+    }
+
+    private ServiceConnection mServConn = new ServiceConnection() {
+
+	@Override
+	public void onServiceDisconnected(ComponentName name) {
+	    mFacade = null;
+	    mIsConnected = false;
+	}
+
+	@Override
+	public void onServiceConnected(ComponentName name, IBinder service) {
+	    // TODO Auto-generated method stub
+	    mFacade = IXMPPFacade.Stub.asInterface(service);
+	    synchronized (mQueue) {
+		for (Message msg : mQueue) {
+		    msg.sendToTarget();
+		}
+		mQueue.clear();
+	    }
+	}
+    };
+
+    public synchronized void stopBeemService() {
+	Intent intent = new Intent(this, BeemService.class);
+	mApplicationContext.unbindService(mServConn);
+	mApplicationContext.stopService(intent);
+    }
+
+    public IXMPPFacade getXmppFacade() {
+	return mFacade;
+    }
+    
+    public void callWhenServiceConnected(Handler target, Runnable callback) {
+	Message msg = Message.obtain(target, callback);
+	if (!mIsConnected) {
+	    msg.sendToTarget();
+	} else {
+	    startBeemService();
+	    synchronized (mQueue) {
+		mQueue.add(msg);
+	    }
+	}
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/beem/project/beem/provider/Beem.java	Wed Apr 01 19:24:05 2009 +0200
@@ -0,0 +1,157 @@
+package com.beem.project.beem.provider;
+
+import android.net.Uri;
+import android.provider.BaseColumns;
+
+/**
+ * Convenience definitions for BEEM's providers
+ */
+public final class Beem {
+
+	public final static String 	AUTHORITY = "com.beem.project.provider";
+
+	public final static String	DB_NAME = "beem.db";
+	public final static int		DB_VERSION = 2;
+
+	public final static String	USERS_TABLE_NAME = "users";
+	public final static String	CONTACTS_TABLE_NAME = "contacts";
+
+	/**
+	 * Constructor
+	 */
+	private Beem() {}
+
+
+	/**
+	 * Users table
+	 */
+	public static final class Users implements BaseColumns {
+		
+		/**
+		 * The query used to create the table
+		 */
+		public final static String	QUERY_CREATE = 
+			"CREATE TABLE " + Beem.USERS_TABLE_NAME + " ("
+			+ Users._ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
+			+ Users.JUSERNAME + " TEXT,"
+			+ Users.DATE_CREATED + " INTEGER,"
+			+ Users.DATE_MODIFIED + " INTEGER"
+			+ ");";
+		
+		/**
+		 * The content:// style URL for Contacts table
+		 */
+		public final static Uri		CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/users");
+
+		/**
+		 * The MIME type of {@link #CONTENT_URI} providing a directory of users.
+		 */
+		public static final String	CONTENT_TYPE = "vnd.android.cursor.dir/vnd.beem.project.user";
+
+		/**
+		 * The MIME type of a {@link #CONTENT_URI} sub-directory of a single user.
+		 */
+		public static final String	CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.beem.project.user";
+
+		/**
+		 * The default sort order for this table
+		 */
+		public final static String 	DEFAULT_SORT_ORDER = "_id ASC";
+
+		/**
+		 * The Jabber username of the user
+		 * <P>Type: TEXT</P>
+		 */
+		public final static String	JUSERNAME = "username";
+		
+		/**
+		 * The timestamp for when the user was created
+		 * <P>Type: INTEGER (long from System.curentTimeMillis())</P>
+		 */
+		public final static String	DATE_CREATED = "created";
+
+		/**
+		 * The timestamp for when the user was last modified
+		 * <P>Type: INTEGER (long from System.curentTimeMillis())</P>
+		 */
+		public final static String	DATE_MODIFIED = "modified";
+	}
+
+
+	/**
+	 * Contacts table
+	 */
+	public static final class Contacts implements BaseColumns {
+
+		/**
+		 * The query used to create the table
+		 */
+		public final static String	QUERY_CREATE = 
+			"CREATE TABLE " + Beem.CONTACTS_TABLE_NAME + " ("
+			+ Contacts._ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
+			+ Contacts.UID + " INTEGER, "
+			+ Contacts.JID + " INTEGER,"
+			+ Contacts.NICKNAME + " TEXT,"
+			+ Contacts.ALIAS + " TEXT,"
+			+ Contacts.DATE_CREATED + " INTEGER,"
+			+ Contacts.DATE_MODIFIED + " INTEGER"
+			+ ");";
+
+		/**
+		 * The content:// style URL for Contacts table
+		 */
+		public final static Uri		CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/contacts");
+
+		/**
+		 * The MIME type of {@link #CONTENT_URI} providing a directory of contacts.
+		 */
+		public static final String	CONTENT_TYPE = "vnd.android.cursor.dir/vnd.beem.project.contact";
+
+		/**
+		 * The MIME type of a {@link #CONTENT_URI} sub-directory of a single contact.
+		 */
+		public static final String	CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.beem.project.contact";
+
+		/**
+		 * The default sort order for this table
+		 */
+		public final static String 	DEFAULT_SORT_ORDER = "nickname ASC";
+
+		/**
+		 * The user id having the contact
+		 * <P>Type: INTEGER</P>
+		 */
+		public final static String	UID = "uid";
+
+		/**
+		 * The JabberID of the contact
+		 * <P>Type: INTEGER</P>
+		 */
+		public final static String	JID = "jid";
+
+		/**
+		 * The nickname of the contact
+		 * <P>Type: TEXT</P>
+		 */
+		public final static String	NICKNAME = "nickname";
+
+		/**
+		 * The alias of the contact
+		 * <P>Type: TEXT</P>
+		 */
+		public final static String	ALIAS = "alias";
+
+		/**
+		 * The timestamp for when the contact was created
+		 * <P>Type: INTEGER (long from System.curentTimeMillis())</P>
+		 */
+		public final static String	DATE_CREATED = "created";
+
+		/**
+		 * The timestamp for when the contact was last modified
+		 * <P>Type: INTEGER (long from System.curentTimeMillis())</P>
+		 */
+		public final static String	DATE_MODIFIED = "modified";
+
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/beem/project/beem/provider/BeemDatabaseHelper.java	Wed Apr 01 19:24:05 2009 +0200
@@ -0,0 +1,34 @@
+package com.beem.project.beem.provider;
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.util.Log;
+
+public class BeemDatabaseHelper extends SQLiteOpenHelper {
+	
+	private String tag;
+	private String tableName;
+	private String creationQuery;
+
+	public BeemDatabaseHelper(Context context, String tag, String tableName, String creationQuery) {
+		super(context, Beem.DB_NAME, null, Beem.DB_VERSION);
+		
+		this.tag = tag;
+		this.tableName = tableName;
+		this.creationQuery = creationQuery;
+	}
+	
+	@Override
+	public void onCreate(SQLiteDatabase db) {
+		db.execSQL(this.creationQuery);
+	}
+
+	@Override
+	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+		Log.w(this.tag, "Upgrading database from version " + oldVersion + " to "
+				+ newVersion + ", which will destroy all old data");
+		db.execSQL("DROP TABLE IF EXISTS " + this.tableName + ";");
+		onCreate(db);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/beem/project/beem/provider/ContactProvider.java	Wed Apr 01 19:24:05 2009 +0200
@@ -0,0 +1,210 @@
+/**
+ * 
+ */
+package com.beem.project.beem.provider;
+
+import java.util.HashMap;
+
+import android.content.ContentProvider;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.UriMatcher;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.database.SQLException;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteQueryBuilder;
+import android.net.Uri;
+import android.text.TextUtils;
+
+/**
+ * @author dasilvj
+ *
+ */
+public class ContactProvider extends ContentProvider {
+
+	private final static String				TAG = "ContactProvider";
+
+	private static HashMap<String, String>	sContactsProjectionMap;
+
+	private static final int				CONTACTS = 1;
+	private static final int				CONTACT_ID = 2;
+
+	private static final UriMatcher			sUriMatcher;
+	private BeemDatabaseHelper				mOpenHelper;
+
+	@Override
+	public int delete(Uri uri, String selection, String[] selectionArgs) {
+		SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+		int count;
+
+		switch (sUriMatcher.match(uri)) {
+		case CONTACTS:
+			count = db.delete(Beem.CONTACTS_TABLE_NAME, selection, selectionArgs);
+			break;
+
+		case CONTACT_ID:
+			String contactId = uri.getPathSegments().get(1);
+			count = db.delete(Beem.CONTACTS_TABLE_NAME, Beem.Contacts._ID + "=" + contactId
+					+ (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""), selectionArgs);
+			break;
+
+		default:
+			throw new IllegalArgumentException("Unknown URI " + uri);
+		}
+
+		getContext().getContentResolver().notifyChange(uri, null);
+		return count;
+	}
+
+	@Override
+	public String getType(Uri uri) {
+		switch (sUriMatcher.match(uri)) {
+		case CONTACTS:
+			return Beem.Contacts.CONTENT_TYPE;
+
+		case CONTACT_ID:
+			return Beem.Contacts.CONTENT_ITEM_TYPE;
+
+		default:
+			throw new IllegalArgumentException("Unknown URI " + uri);
+		}
+	}
+
+	@Override
+	public Uri insert(Uri uri, ContentValues initialValues) {
+        // Validate the requested uri
+        if (sUriMatcher.match(uri) != CONTACTS) {
+            throw new IllegalArgumentException("Unknown URI " + uri);
+        }
+
+        ContentValues values;
+        if (initialValues != null) {
+            values = new ContentValues(initialValues);
+        } else {
+            values = new ContentValues();
+        }
+
+        Long now = Long.valueOf(System.currentTimeMillis());
+
+        // Make sure that the fields are all set
+        if (values.containsKey(Beem.Contacts.UID) == false) {
+        	// TODO :: Must check that the UID exists using UserProvider
+            throw new SQLException("No UID specified. Failed to insert row into " + uri);
+        }
+
+        if (values.containsKey(Beem.Contacts.JID) == false) {
+            values.put(Beem.Contacts.JID, "");
+        }
+        
+        if (values.containsKey(Beem.Contacts.NICKNAME) == false) {
+            values.put(Beem.Contacts.JID, "");
+        }
+        
+        if (values.containsKey(Beem.Contacts.ALIAS) == false) {
+            values.put(Beem.Contacts.JID, "");
+        }
+        
+        if (values.containsKey(Beem.Contacts.DATE_CREATED) == false) {
+            values.put(Beem.Contacts.DATE_CREATED, now);
+        }
+
+        if (values.containsKey(Beem.Contacts.DATE_MODIFIED) == false) {
+            values.put(Beem.Contacts.DATE_MODIFIED, now);
+        }
+
+        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+        long rowId = db.insert(Beem.CONTACTS_TABLE_NAME, Beem.Contacts._ID, values);
+        if (rowId > 0) {
+            Uri contactUri = ContentUris.withAppendedId(Beem.Contacts.CONTENT_URI, rowId);
+            getContext().getContentResolver().notifyChange(contactUri, null);
+            return contactUri;
+        }
+
+        throw new SQLException("Failed to insert row into " + uri);
+	}
+
+	@Override
+	public boolean onCreate() {
+		mOpenHelper = new BeemDatabaseHelper(getContext(), TAG, Beem.CONTACTS_TABLE_NAME, Beem.Contacts.QUERY_CREATE);
+		return true;
+	}
+
+	@Override
+	public Cursor query(Uri uri, String[] projection, String selection,
+			String[] selectionArgs, String sortOrder) {
+		SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
+
+		switch (sUriMatcher.match(uri)) {
+		case CONTACTS:
+			qb.setTables(Beem.CONTACTS_TABLE_NAME);
+			qb.setProjectionMap(sContactsProjectionMap);
+			break;
+
+		case CONTACT_ID:
+			qb.setTables(Beem.USERS_TABLE_NAME);
+			qb.setProjectionMap(sContactsProjectionMap);
+			qb.appendWhere(Beem.Contacts._ID + "=" + uri.getPathSegments().get(1));
+			break;
+
+		default:
+			throw new IllegalArgumentException("Unknown URI " + uri);        
+		}
+
+		// If no sort order is specified use the default
+		String orderBy;
+		if (TextUtils.isEmpty(sortOrder)) {
+			orderBy = Beem.Contacts.DEFAULT_SORT_ORDER;
+		} else {
+			orderBy = sortOrder;
+		}
+
+		// Get the database and run the query
+		SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+		Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, orderBy);
+
+		// Tell the cursor what uri to watch, so it knows when its source data changes
+		c.setNotificationUri(getContext().getContentResolver(), uri);
+		return c;
+	}
+
+	@Override
+	public int update(Uri uri, ContentValues values, String selection,
+			String[] selectionArgs) {
+        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+        int count;
+        
+        switch (sUriMatcher.match(uri)) {
+        case CONTACTS:
+            count = db.update(Beem.CONTACTS_TABLE_NAME, values, selection, selectionArgs);
+            break;
+
+        case CONTACT_ID:
+            String contactId = uri.getPathSegments().get(1);
+            count = db.update(Beem.CONTACTS_TABLE_NAME, values, Beem.Contacts._ID + "=" + contactId
+                    + (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""), selectionArgs);
+            break;
+
+        default:
+            throw new IllegalArgumentException("Unknown URI " + uri);
+        }
+
+        getContext().getContentResolver().notifyChange(uri, null);
+        return count;
+	}
+
+	static {
+		sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
+		sUriMatcher.addURI(Beem.AUTHORITY, "contacts", CONTACTS);
+		sUriMatcher.addURI(Beem.AUTHORITY, "contacts/#", CONTACT_ID);
+
+		sContactsProjectionMap = new HashMap<String, String>();
+		sContactsProjectionMap.put(Beem.Contacts._ID, Beem.Contacts._ID);
+		sContactsProjectionMap.put(Beem.Contacts.UID, Beem.Contacts.UID);
+		sContactsProjectionMap.put(Beem.Contacts.JID, Beem.Contacts.JID);
+		sContactsProjectionMap.put(Beem.Contacts.NICKNAME, Beem.Contacts.NICKNAME);
+		sContactsProjectionMap.put(Beem.Contacts.ALIAS, Beem.Contacts.ALIAS);
+		sContactsProjectionMap.put(Beem.Contacts.DATE_CREATED, Beem.Contacts.DATE_CREATED);
+		sContactsProjectionMap.put(Beem.Contacts.DATE_MODIFIED, Beem.Contacts.DATE_MODIFIED);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/beem/project/beem/provider/UserProvider.java	Wed Apr 01 19:24:05 2009 +0200
@@ -0,0 +1,186 @@
+package com.beem.project.beem.provider;
+
+import java.util.HashMap;
+
+import android.content.ContentProvider;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.UriMatcher;
+import android.database.Cursor;
+import android.database.SQLException;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteQueryBuilder;
+import android.net.Uri;
+import android.text.TextUtils;
+
+public class UserProvider extends ContentProvider {
+
+	private final static String				TAG = "UserProvider";
+
+	private static HashMap<String, String>	sUsersProjectionMap;
+
+	private static final int				USERS = 1;
+	private static final int				USER_ID = 2;
+
+	private static final UriMatcher			sUriMatcher;
+	private BeemDatabaseHelper				mOpenHelper;
+
+	@Override
+	public int delete(Uri uri, String selection, String[] selectionArgs) {
+		SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+		int count;
+
+		switch (sUriMatcher.match(uri)) {
+		case USERS:
+			count = db.delete(Beem.USERS_TABLE_NAME, selection, selectionArgs);
+			break;
+
+		case USER_ID:
+			String userID = uri.getPathSegments().get(1);
+			count = db.delete(Beem.USERS_TABLE_NAME, Beem.Users._ID + "=" + userID
+					+ (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""), selectionArgs);
+			break;
+
+		default:
+			throw new IllegalArgumentException("Unknown URI " + uri);
+		}
+
+		getContext().getContentResolver().notifyChange(uri, null);
+		return count;
+	}
+
+	@Override
+	public String getType(Uri uri) {
+		switch (sUriMatcher.match(uri)) {
+		case USERS:
+			return Beem.Users.CONTENT_TYPE;
+
+		case USER_ID:
+			return Beem.Users.CONTENT_ITEM_TYPE;
+
+		default:
+			throw new IllegalArgumentException("Unknown URI " + uri);
+		}
+	}
+
+	@Override
+	public Uri insert(Uri uri, ContentValues initialValues) {
+        // Validate the requested uri
+        if (sUriMatcher.match(uri) != USERS) {
+            throw new IllegalArgumentException("Unknown URI " + uri);
+        }
+
+        ContentValues values;
+        if (initialValues != null) {
+            values = new ContentValues(initialValues);
+        } else {
+            values = new ContentValues();
+        }
+
+        Long now = Long.valueOf(System.currentTimeMillis());
+
+        // Make sure that the fields are all set
+        if (values.containsKey(Beem.Users.JUSERNAME) == false) {
+            throw new SQLException("No JUSERNAME specified. Failed to insert row into " + uri);
+        }
+        
+        if (values.containsKey(Beem.Users.DATE_CREATED) == false) {
+            values.put(Beem.Users.DATE_CREATED, now);
+        }
+
+        if (values.containsKey(Beem.Users.DATE_MODIFIED) == false) {
+            values.put(Beem.Users.DATE_MODIFIED, now);
+        }
+
+        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+        long rowId = db.insert(Beem.USERS_TABLE_NAME, Beem.Users._ID, values);
+        if (rowId > 0) {
+            Uri userUri = ContentUris.withAppendedId(Beem.Users.CONTENT_URI, rowId);
+            getContext().getContentResolver().notifyChange(userUri, null);
+            return userUri;
+        }
+
+        throw new SQLException("Failed to insert row into " + uri);
+	}
+
+	@Override
+	public boolean onCreate() {
+		mOpenHelper = new BeemDatabaseHelper(getContext(), TAG, Beem.USERS_TABLE_NAME, Beem.Users.QUERY_CREATE);
+		return true;
+	}
+
+	@Override
+	public Cursor query(Uri uri, String[] projection, String selection,
+			String[] selectionArgs, String sortOrder) {
+		SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
+
+		switch (sUriMatcher.match(uri)) {
+		case USERS:
+			qb.setTables(Beem.USERS_TABLE_NAME);
+			qb.setProjectionMap(sUsersProjectionMap);
+			break;
+
+		case USER_ID:
+			qb.setTables(Beem.USERS_TABLE_NAME);
+			qb.setProjectionMap(sUsersProjectionMap);
+			qb.appendWhere(Beem.Users._ID + "=" + uri.getPathSegments().get(1));
+			break;
+
+		default:
+			throw new IllegalArgumentException("Unknown URI " + uri);        
+		}
+
+		// If no sort order is specified use the default
+		String orderBy;
+		if (TextUtils.isEmpty(sortOrder)) {
+			orderBy = Beem.Users.DEFAULT_SORT_ORDER;
+		} else {
+			orderBy = sortOrder;
+		}
+
+		// Get the database and run the query
+		SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+		Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, orderBy);
+
+		// Tell the cursor what uri to watch, so it knows when its source data changes
+		c.setNotificationUri(getContext().getContentResolver(), uri);
+		return c;
+	}
+
+	@Override
+	public int update(Uri uri, ContentValues values, String selection,
+			String[] selectionArgs) {
+        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+        int count;
+        
+        switch (sUriMatcher.match(uri)) {
+        case USERS:
+            count = db.update(Beem.USERS_TABLE_NAME, values, selection, selectionArgs);
+            break;
+
+        case USER_ID:
+            String userId = uri.getPathSegments().get(1);
+            count = db.update(Beem.USERS_TABLE_NAME, values, Beem.Users._ID + "=" + userId
+                    + (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""), selectionArgs);
+            break;
+
+        default:
+            throw new IllegalArgumentException("Unknown URI " + uri);
+        }
+
+        getContext().getContentResolver().notifyChange(uri, null);
+        return count;
+	}
+
+	static {
+		sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
+		sUriMatcher.addURI(Beem.AUTHORITY, "users", USERS);
+		sUriMatcher.addURI(Beem.AUTHORITY, "users/#", USER_ID);
+
+		sUsersProjectionMap = new HashMap<String, String>();
+		sUsersProjectionMap.put(Beem.Users._ID, Beem.Users._ID);
+		sUsersProjectionMap.put(Beem.Users.JUSERNAME, Beem.Users.JUSERNAME);
+		sUsersProjectionMap.put(Beem.Users.DATE_CREATED, Beem.Users.DATE_CREATED);
+		sUsersProjectionMap.put(Beem.Users.DATE_MODIFIED, Beem.Users.DATE_MODIFIED);
+	}
+}
--- a/src/com/beem/project/beem/ui/Beem.java	Fri Mar 27 18:12:43 2009 +0100
+++ b/src/com/beem/project/beem/ui/Beem.java	Wed Apr 01 19:24:05 2009 +0200
@@ -12,6 +12,7 @@
 import android.view.View.OnClickListener;
 import android.widget.Button;
 
+import com.beem.project.beem.BeemApplication;
 import com.beem.project.beem.R;
 
 /**
@@ -23,6 +24,7 @@
     private BeemDialogSettings mDialog;
     private Button mButton;
     private Handler mHandler;
+    private BeemApplication mBeemApplication;
 
     /**
      * Default constructor.
@@ -40,6 +42,7 @@
     @Override
     public final void onCreate(Bundle savedInstanceState) {
 	super.onCreate(savedInstanceState);
+	mBeemApplication = BeemApplication.getApplication(this);
 	setContentView(R.layout.beem);
 	mSettings = getSharedPreferences(
 		getString(R.string.PreferenceFileName), MODE_PRIVATE);
@@ -52,7 +55,7 @@
 		if (mButton.getText() == getString(R.string.BeemCreateAccount))
 		    mDialog.show();
 		else
-		    startActivity(new Intent(Beem.this, ContactList.class));
+		    startActivity(new Intent(Beem.this, ContactList.class));	    
 	    }
 	});
 	showJID();
--- a/src/com/beem/project/beem/ui/ContactList.java	Fri Mar 27 18:12:43 2009 +0100
+++ b/src/com/beem/project/beem/ui/ContactList.java	Wed Apr 01 19:24:05 2009 +0200
@@ -4,91 +4,154 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-
 import android.app.ExpandableListActivity;
-import android.content.ComponentName;
+import android.content.Context;
 import android.content.Intent;
-import android.content.ServiceConnection;
+import android.graphics.drawable.Drawable;
 import android.os.Bundle;
-import android.os.IBinder;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.Log;
 import android.view.View;
+import android.view.ViewGroup;
 import android.widget.ExpandableListAdapter;
 import android.widget.ExpandableListView;
+import android.widget.ImageView;
 import android.widget.SimpleExpandableListAdapter;
-
-import com.beem.project.beem.BeemService;
+import android.widget.TextView;
+import com.beem.project.beem.BeemApplication;
 import com.beem.project.beem.R;
+import com.beem.project.beem.service.Contact;
 import com.beem.project.beem.service.aidl.IXMPPFacade;
 
 public class ContactList extends ExpandableListActivity {
 
+    private static final String TAG = "CONTACTLIST_ACT";
     private IXMPPFacade mService = null;
+    private Handler mHandler;
+    private BeemApplication mBeemApplication;
+
+    @Override
+    public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
+	startActivity(new Intent(this, SendIM.class));
+	return true;
+
+    };
 
     @Override
     public void onCreate(Bundle saveBundle) {
 	super.onCreate(saveBundle);
-	bindService(new Intent(this, BeemService.class), mConnection,
-		BIND_AUTO_CREATE | BIND_DEBUG_UNBIND);
-	showContactList();
+	mHandler = new Handler();
+	mBeemApplication = BeemApplication.getApplication(this);
+
     }
 
     @Override
-    public boolean onChildClick(ExpandableListView parent,
-	    View v, int groupPosition, int childPosition, long id) {
-	startActivity(new Intent(this, SendIM.class));
-		return true;
+    public void onStart() {
+	super.onStart();
+	mBeemApplication.startBeemService();
+	mBeemApplication.callWhenServiceConnected(mHandler, new Runnable() {
+	    @Override
+	    public void run() {
+		mService = mBeemApplication.getXmppFacade();
+		try {
+		    showContactList(mService.getRoster().getContactList(), mService.getRoster().getContactList());
+		} catch (RemoteException e) {
+		    // TODO Auto-generated catch block
+		    e.printStackTrace();
+		}
 
-    };
+	    }
+	});
+    }
 
-    private void showContactList() {
+    private void showContactList(List<Contact> listGroup, List<Contact> listContact) {
 	ExpandableListAdapter Adapter;
-
 	List<Map<String, String>> groupData = new ArrayList<Map<String, String>>();
 	List<List<Map<String, String>>> childData = new ArrayList<List<Map<String, String>>>();
 
-	for (int i = 0; i < 2; i++) {
+	if (listGroup.size() == 0)
+	    listGroup.add(new Contact());
+	for (int i = 0; i < listGroup.size(); i++) {
 	    Map<String, String> curGroupMap = new HashMap<String, String>();
+
 	    groupData.add(curGroupMap);
-	    curGroupMap.put("NAME", "Group " + i);
+	    curGroupMap.put("NAME", "Default");
 
 	    List<Map<String, String>> children = new ArrayList<Map<String, String>>();
-	    for (int j = 0; j < 5; j++) {
+	    for (int j = 0; j < listContact.size(); ++j) {
 		Map<String, String> curChildMap = new HashMap<String, String>();
 		children.add(curChildMap);
-		curChildMap.put("NAME CHILD", "Child " + j);
+		curChildMap.put("NAME_CHILD", listContact.get(j).getJID());
 		curChildMap.put("MSG", "Taper votre message perso");
 	    }
 	    childData.add(children);
 	}
 
-	Adapter = new SimpleExpandableListAdapter(this, groupData,
-		R.layout.contactlistgroup, new String[] { "NAME" },
-		new int[] { R.id.textgroup }, childData, R.layout.contactlist,
-		new String[] { "NAME CHILD", "MSG" }, new int[] {
-			R.id.textchild1, R.id.textchild2 });
+	Adapter = new ContactExpandableListAdapter(this, groupData, R.layout.contactlistgroup, new String[] { "NAME" },
+	    new int[] { R.id.textgroup }, childData, R.layout.contactlistcontact, new String[] { "NAME_CHILD", "MSG" },
+	    new int[] { R.id.textchild1, R.id.textchild2, R.id.avatar });
 	setListAdapter(Adapter);
     }
 
-    private ServiceConnection mConnection = new ServiceConnection() {
-	@Override
-	public void onServiceConnected(ComponentName name, IBinder service) {
-	    mService = IXMPPFacade.Stub.asInterface(service);
-	    /*
-	     * mService.getGroupList(); mService.getContactList();
-	     */
-	    showContactList();
+    /**
+     * A simple adapter which allows you to bind data to specific Views defined within the layout of an Expandable Lists
+     * children (Implement getGroupView() to define the layout of parents)
+     */
+    public class ContactExpandableListAdapter extends SimpleExpandableListAdapter {
+
+	private List<? extends List<? extends Map<String, ?>>> mChildData;
+	private String[] mChildFrom;
+	private int[] mChildTo;
+
+	public ContactExpandableListAdapter(Context context, List<? extends Map<String, ?>> groupData, int groupLayout,
+	    String[] groupFrom, int[] groupTo, List<? extends List<? extends Map<String, ?>>> childData,
+	    int childLayout, String[] childFrom, int[] childTo) {
+	    super(context, groupData, groupLayout, groupFrom, groupTo, childData, childLayout, childFrom, childTo);
+
+	    mChildData = childData;
+	    mChildFrom = childFrom;
+	    mChildTo = childTo;
+
 	}
 
 	@Override
-	public void onServiceDisconnected(ComponentName name) {
+	public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView,
+	    ViewGroup parent) {
+
+	    View v;
+	    if (convertView == null) {
+		v = newChildView(isLastChild, parent);
+	    } else {
+		v = convertView;
+	    }
+	    bindView(v, mChildData.get(groupPosition).get(childPosition), mChildFrom, mChildTo, groupPosition,
+		childPosition);
+	    return v;
 	}
 
-    };
-
-    @Override
-    public void onDestroy() {
-	super.onDestroy();
-	unbindService(mConnection);
+	// This method binds my data to the Views specified in the child
+	// xmllayout
+	private void bindView(View view, Map<String, ?> data, String[] from, int[] to, int groupPosition,
+	    int childPosition) {
+	    // Apply TextViews
+	    TextView v1 = (TextView) view.findViewById(to[0]);
+	    if (v1 != null) {
+		Log.i("CONTACT LIST 1", (String) data.get(from[0]) + " " + to[0]);
+		v1.setText((String) data.get(from[0]));
+	    }
+	    TextView v2 = (TextView) view.findViewById(to[1]);
+	    if (v2 != null) {
+		Log.i("CONTACT LIST 2", (String) data.get(from[1]) + " " + to[1]);
+		v2.setText((String) data.get(from[1]));
+	    }
+	    // Apply ImageView
+	    ImageView imgV = (ImageView) view.findViewById(to[2]);
+	    if (imgV != null) {
+		Drawable avatar = (Drawable) getResources().getDrawable(R.drawable.avatar);
+		imgV.setImageDrawable(avatar);
+	    }
+	}
     }
 
 }