Implements swiping on contact list by using android compat ViewPager
authorDa Risk <da_risk@beem-project.com>
Wed, 29 Feb 2012 00:53:20 +0100
changeset 993 02aafc8b2220
parent 992 142f330bd3f6
child 994 7483a66399de
Implements swiping on contact list by using android compat ViewPager
libs/android-support-v13.jar
project.properties
res/layout/contactlist.xml
src/com/beem/project/beem/ui/ContactList.java
src/com/beem/project/beem/ui/ContactListAdapter.java
src/com/beem/project/beem/ui/ContactListFragment.java
Binary file libs/android-support-v13.jar has changed
--- a/project.properties	Fri Apr 06 17:43:01 2012 +0200
+++ b/project.properties	Wed Feb 29 00:53:20 2012 +0100
@@ -8,4 +8,4 @@
 # project structure.
 
 # Project target.
-target=android-8
+target=android-15
--- a/res/layout/contactlist.xml	Fri Apr 06 17:43:01 2012 +0200
+++ b/res/layout/contactlist.xml	Wed Feb 29 00:53:20 2012 +0100
@@ -4,12 +4,21 @@
 	android:orientation="vertical">
 	<ViewStub android:id="@+id/contactlist_stub" android:inflatedId="@+id/contactlist_groupstub" android:layout_width="fill_parent"
 		android:layout_height="wrap_content" android:layout="@layout/contactlist_groupstub"/>
+		
+		<!-- 
+	
 	<LinearLayout android:layout_width="fill_parent"
 		android:layout_height="fill_parent" android:orientation="horizontal"
 		android:padding="2px">
 		<ListView android:id="@+id/contactlist" android:layout_width="fill_parent"
 		    android:layout_height="fill_parent" android:transcriptMode="disabled"
 		    android:textFilterEnabled="true" />
-
 	</LinearLayout>
+	 	-->
+	 	
+	 	<android.support.v4.view.ViewPager android:id="@+id/pager"
+	 	    android:layout_width="fill_parent"
+	 	    android:layout_height="fill_parent"
+	 	    android:padding="2px"/>
+	
 </LinearLayout>
--- a/src/com/beem/project/beem/ui/ContactList.java	Fri Apr 06 17:43:01 2012 +0200
+++ b/src/com/beem/project/beem/ui/ContactList.java	Wed Feb 29 00:53:20 2012 +0100
@@ -42,33 +42,36 @@
 */
 package com.beem.project.beem.ui;
 
+import java.io.IOException;
+import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Comparator;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
-import java.io.InputStream;
-import java.io.IOException;
 
 import org.jivesoftware.smack.util.StringUtils;
 
-import android.app.Activity;
 import android.app.Dialog;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.SharedPreferences;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
 import android.net.Uri;
 import android.os.Bundle;
-import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.preference.PreferenceManager;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentPagerAdapter;
+import android.support.v4.view.ViewPager;
 import android.util.Log;
-import android.view.ContextMenu;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuInflater;
@@ -77,7 +80,6 @@
 import android.view.ViewGroup;
 import android.view.ViewStub;
 import android.widget.AdapterView;
-import android.widget.AdapterView.AdapterContextMenuInfo;
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.BaseAdapter;
 import android.widget.Filter;
@@ -85,13 +87,10 @@
 import android.widget.Gallery;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
-import android.widget.ListView;
 import android.widget.TextView;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LayerDrawable;
 
+import com.beem.project.beem.BeemApplication;
 import com.beem.project.beem.R;
-import com.beem.project.beem.BeemApplication;
 import com.beem.project.beem.providers.AvatarProvider;
 import com.beem.project.beem.service.Contact;
 import com.beem.project.beem.service.PresenceAdapter;
@@ -104,13 +103,11 @@
 import com.beem.project.beem.ui.dialogs.builders.DeleteContact;
 import com.beem.project.beem.ui.dialogs.builders.ResendSubscription;
 import com.beem.project.beem.utils.BeemBroadcastReceiver;
-import com.beem.project.beem.utils.SortedList;
-import com.beem.project.beem.utils.Status;
 
 /**
  * The contact list activity displays the roster of the user.
  */
-public class ContactList extends Activity {
+public class ContactList extends FragmentActivity {
 
     private static final Intent SERVICE_INTENT = new Intent();
     static {
@@ -118,19 +115,15 @@
     }
 
     private static final String TAG = "ContactList";
-    private final BeemContactList mAdapterContactList = new BeemContactList();
     private final List<String> mListGroup = new ArrayList<String>();
 
     /** Map containing a list of the different contacts of a given group.
      * Each list is a @{link SortedList} so there is no need to sort it again.
      * */
     private final Map<String, List<Contact>> mContactOnGroup = new HashMap<String, List<Contact>>();
-    private final BeemContactListOnClick mOnContactClick = new BeemContactListOnClick();
-    private final Handler mHandler = new Handler();
     private final ServiceConnection mServConn = new BeemServiceConnection();
     private final BeemBroadcastReceiver mReceiver = new BeemBroadcastReceiver();
-    private final ComparatorContactListByStatusAndName<Contact> mComparator =
-	new ComparatorContactListByStatusAndName<Contact>();
+
     private final BeemRosterListener mBeemRosterListener = new BeemRosterListener();
     private List<Contact> mListContact;
     private String mSelectedGroup;
@@ -142,6 +135,10 @@
     private LayoutInflater mInflater;
     private BeemBanner mAdapterBanner;
     private boolean mBinded;
+    private ViewPager viewPager;
+    private Map<String, ContactListAdapter> contactListAdapters = new HashMap<String, ContactListAdapter>();
+    private ListPagerAdapter groupsPagesAdapter;
+    private Gallery groupGallery;
 
     /**
      * Constructor.
@@ -194,86 +191,6 @@
 	}
     }
 
-    @Override
-    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
-	super.onCreateContextMenu(menu, v, menuInfo);
-	MenuInflater inflater = getMenuInflater();
-	inflater.inflate(R.menu.contactlist_context, menu);
-	AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
-	Contact c = mListContact.get(info.position);
-	try {
-	    mSelectedContact = mRoster.getContact(c.getJID());
-	} catch (RemoteException e) {
-	    e.printStackTrace();
-	}
-	menu.setHeaderTitle(mSelectedContact.getJID());
-    }
-
-    @Override
-    public boolean onContextItemSelected(MenuItem item) {
-	Intent in;
-	boolean result;
-	if (mSelectedContact != null) {
-	    switch (item.getItemId()) {
-		case R.id.contact_list_context_menu_chat_item:
-		    List<String> res = mSelectedContact.getMRes();
-		    if (res.isEmpty()) {
-			result = false;
-			break;
-		    }
-		    for (String resv : res) {
-			in = new Intent(this, Chat.class);
-			in.setData(mSelectedContact.toUri(resv));
-			item.getSubMenu().add(resv).setIntent(in);
-		    }
-		    result = true;
-		    break;
-		case R.id.contact_list_context_menu_call_item:
-		    try {
-			mXmppFacade.call(mSelectedContact.getJID() + "/psi");
-			result = true;
-		    } catch (RemoteException e) {
-			e.printStackTrace();
-		    }
-		    result = true;
-		    break;
-		case R.id.contact_list_context_menu_user_info:
-		    item.getSubMenu().setHeaderTitle(mSelectedContact.getJID());
-		    result = true;
-		    break;
-		case R.id.contact_list_context_menu_userinfo_alias:
-		    Dialog alias = new Alias(ContactList.this, mRoster, mSelectedContact).create();
-		    alias.show();
-		    result = true;
-		    break;
-		case R.id.contact_list_context_menu_userinfo_group:
-		    in = new Intent(this, GroupList.class);
-		    in.putExtra("contact", mSelectedContact);
-		    startActivity(in);
-		    result = true;
-		    break;
-		case R.id.contact_list_context_menu_userinfo_subscription:
-		    Dialog subscription = new ResendSubscription(ContactList.this,
-			mXmppFacade, mSelectedContact).create();
-		    subscription.show();
-		    result = true;
-		    break;
-		case R.id.contact_list_context_menu_userinfo_block:
-		    result = true;
-		    break;
-		case R.id.contact_list_context_menu_userinfo_delete:
-		    Dialog delete = new DeleteContact(ContactList.this, mRoster, mSelectedContact).create();
-		    delete.show();
-		    result = true;
-		    break;
-		default:
-		    result = super.onContextItemSelected(item);
-		    break;
-	    }
-	    return result;
-	}
-	return super.onContextItemSelected(item);
-    }
 
     @Override
     protected void onCreate(Bundle saveBundle) {
@@ -284,17 +201,25 @@
 	this.registerReceiver(mReceiver, new IntentFilter(BeemBroadcastReceiver.BEEM_CONNECTION_CLOSED));
 
 	mInflater = getLayoutInflater();
-	mAdapterBanner = new BeemBanner(mInflater, mListGroup);
+	mAdapterBanner = new BeemBanner();
 	mListContact = new ArrayList<Contact>();
-	ListView listView = (ListView) findViewById(R.id.contactlist);
-	listView.setOnItemClickListener(mOnContactClick);
-	registerForContextMenu(listView);
-	listView.setAdapter(mAdapterContactList);
+	
+	viewPager = (ViewPager) findViewById(R.id.pager);
+	groupsPagesAdapter = new ListPagerAdapter(getSupportFragmentManager(), viewPager);
+	
+    mListGroup.add(getString(R.string.contact_list_all_contact));
+    mListGroup.add(getString(R.string.contact_list_no_group));
+    mAdapterBanner.notifyDataSetChanged();
     }
 
     @Override
-    protected void onResume() {
-	super.onResume();
+    protected void onStart() {
+	super.onStart();
+	  if (!mSettings.getBoolean(BeemApplication.HIDE_GROUPS_KEY, false))
+			showGroups();
+		    else
+			hideGroups();
+
 	if (!mBinded)
 	    mBinded = bindService(SERVICE_INTENT, mServConn, BIND_AUTO_CREATE);
     }
@@ -328,17 +253,6 @@
     }
 
     /**
-     * Build and display the contact list.
-     * @param group name of the contact list.
-     */
-    private void buildContactList(String group) {
-	mListContact = mContactOnGroup.get(group);
-	mSelectedGroup = group;
-	Log.d(TAG, "buildContactList for group " + group);
-	mAdapterContactList.notifyDataSetChanged();
-    }
-
-    /**
      * Show the groups view.
      */
     private void showGroups() {
@@ -346,14 +260,14 @@
 	ViewStub stub = (ViewStub) findViewById(R.id.contactlist_stub);
 	if (stub != null) {
 	    View v = stub.inflate();
-	    Gallery g = (Gallery) v.findViewById(R.id.contactlist_banner);
-	    g.setOnItemClickListener(new OnItemClickGroupName());
-	    g.setAdapter(mAdapterBanner);
-	    g.setSelection(0);
+	    groupGallery = (Gallery) v.findViewById(R.id.contactlist_banner);
+	    groupGallery.setOnItemClickListener(new OnItemClickGroupName());
+	    groupGallery.setAdapter(mAdapterBanner);
+	    groupGallery.setSelection(0);
 	} else {
 	    ((LinearLayout) findViewById(R.id.contactlist_groupstub)).setVisibility(View.VISIBLE);
-	    Gallery g = (Gallery) findViewById(R.id.contactlist_banner);
-	    g.setSelection(0);
+	    groupGallery = (Gallery) findViewById(R.id.contactlist_banner);
+	    groupGallery.setSelection(0);
 	}
     }
 
@@ -366,7 +280,59 @@
 	    v.setVisibility(View.GONE);
     }
 
+    ContactListAdapter getContactListAdapter(String group) {
+		synchronized (contactListAdapters) {
+			ContactListAdapter contactListAdapter = contactListAdapters.get(group);
+			if (contactListAdapter == null) {
+				contactListAdapter = new ContactListAdapter(ContactList.this);
+				contactListAdapters.put(group, contactListAdapter);
+				if (!mListGroup.contains(group)) {
+					mListGroup.add(mListGroup.size() - 1, group);
+					groupsPagesAdapter.notifyDataSetChanged();
+				    mAdapterBanner.notifyDataSetChanged();
+				}
+			}
+		    boolean hideDisconnected = mSettings.getBoolean(BeemApplication.SHOW_OFFLINE_CONTACTS_KEY, false);
+		    contactListAdapter.setOnlineOnly(hideDisconnected);
+			return contactListAdapter;
+		}
+	}
+    
     /**
+	 * Remove old groups on the banner.
+	 * @throws RemoteException if an error occur when communicating with the service
+	 */
+	private void cleanBannerGroup() throws RemoteException {
+		if (mListGroup.size() <= 2)
+			return;
+	    List<String> rosterGroups = mRoster.getGroupsNames();
+	    List<String> realGroups = mListGroup.subList(1, mListGroup.size() - 1);
+	    realGroups.clear();
+	    realGroups.addAll(rosterGroups);
+	    mAdapterBanner.notifyDataSetChanged();
+	    groupsPagesAdapter.notifyDataSetChanged();
+	}
+
+	/**
+	 * Add a contact to the special list No Group and All contacts.
+	 * The contact will be added if the list is not the current list otherwise
+	 * the list must be modified in a Handler.
+	 *
+	 * @param contact the contact to add.
+	 */
+	private void addToSpecialList(Contact contact) {
+	    List<String> groups = contact.getGroups();
+	    
+	    ContactListAdapter adapter = getContactListAdapter(getString(R.string.contact_list_all_contact));
+	    adapter.put(contact);
+	    if (groups.isEmpty()) {
+	    	adapter = getContactListAdapter(getString(R.string.contact_list_no_group));
+	    	adapter.put(contact);
+	    }
+	    
+	}
+
+	/**
      * Listener on service event.
      */
     private class BeemRosterListener extends IBeemRosterListener.Stub {
@@ -387,30 +353,11 @@
 	 */
 	@Override
 	public void onEntriesAdded(final List<String> addresses) throws RemoteException {
-	    final boolean hideDisconnected = mSettings.getBoolean(BeemApplication.SHOW_OFFLINE_CONTACTS_KEY, false);
 	    for (String newName : addresses) {
-		Contact contact = mRoster.getContact(newName);
-		boolean visible = !hideDisconnected || Status.statusOnline(contact.getStatus());
-		List<String> groups = contact.getGroups();
-		if (visible) {
-		    for (String group : groups) {
-			if (!mListGroup.contains(group)) {
-			    mListGroup.add(mListGroup.size() - 1, group);
-			    List<Contact> tmplist = new SortedList<Contact>(new LinkedList<Contact>(), mComparator);
-			    mContactOnGroup.put(group, tmplist);
-			}
-			List<Contact> contactByGroups = mContactOnGroup.get(group);
-			if (mSelectedGroup.equals(group)) {
-			    updateCurrentList(group, contact);
-			    continue;
-			}
-			contactByGroups.add(contact);
-		    }
-
-		    // add the contact to all and no groups
-		    addToSpecialList(contact);
-		}
+	    	final Contact contact = mRoster.getContact(StringUtils.parseBareAddress(newName));
+	    	putContactInList(contact);
 	    }
+	   
 	}
 
 	/**
@@ -424,26 +371,18 @@
 	public void onEntriesDeleted(final List<String> addresses) throws RemoteException {
 	    Log.d(TAG, "onEntries deleted " + addresses);
 	    for (String cToDelete : addresses) {
-		Contact contact = new Contact(cToDelete);
-		for (Map.Entry<String, List<Contact>> entry : mContactOnGroup.entrySet()) {
-		    List<Contact> contactByGroups = entry.getValue();
-		    if (mSelectedGroup.equals(entry.getKey())) {
-			updateCurrentList(entry.getKey(), contact);
-			continue;
-		    }
-		    contactByGroups.remove(contact);
+		final Contact contact = new Contact(cToDelete);
+		for (final ContactListAdapter adapter : contactListAdapters.values()) {
+			runOnUiThread(new Runnable() {
+				
+				@Override
+				public void run() {
+					adapter.remove(contact);					
+				}
+			});
 		}
+	    }
 		cleanBannerGroup();
-	    }
-
-	    mHandler.post(new Runnable() {
-		public void run() {
-		    mSelectedGroup = getString(R.string.contact_list_all_contact);
-		    mListContact = mContactOnGroup.get(mSelectedGroup);
-
-		    mAdapterContactList.notifyDataSetChanged();
-		}
-	    });
 
 	}
 
@@ -458,38 +397,18 @@
 	 */
 	@Override
 	public void onEntriesUpdated(final List<String> addresses) throws RemoteException {
-	    final boolean hideDisconnected = mSettings.getBoolean(BeemApplication.SHOW_OFFLINE_CONTACTS_KEY, false);
-	    for (String adr : addresses) {
-		Contact contact = mRoster.getContact(adr);
-		boolean visible = !hideDisconnected || Status.statusOnline(contact.getStatus());
-		List<String> groups = contact.getGroups();
-		for (Map.Entry<String, List<Contact>> entry : mContactOnGroup.entrySet()) {
-		    List<Contact> contactByGroups = entry.getValue();
-		    if (mSelectedGroup.equals(entry.getKey())) {
-			updateCurrentList(entry.getKey(), contact);
-			continue;
-		    }
-		    contactByGroups.remove(contact);
-		    if (visible) {
-			for (String group : groups) {
-			    if (!mListGroup.contains(group)) {
-				mListGroup.add(mListGroup.size() - 1, group);
-				List<Contact> tmplist = new SortedList<Contact>(
-				    new LinkedList<Contact>(), mComparator);
-				mContactOnGroup.put(group, tmplist);
-			    }
-			    mContactOnGroup.get(group).remove(contact);
-			}
-		    }
-
-		}
-
-		// add the contact to all and no groups
-		if (visible) {
-		    addToSpecialList(contact);
+	    Log.d(TAG, "onEntries updated " + addresses);
+	    for (String cToDelete : addresses) {
+		Contact contact = new Contact(cToDelete);
+		for (ContactListAdapter adapter : contactListAdapters.values()) {
+			adapter.remove(contact);
 		}
 	    }
-	    cleanBannerGroup();
+	    for (String newName : addresses) {
+	    	final Contact contact = mRoster.getContact(StringUtils.parseBareAddress(newName));
+		    putContactInList(contact);
+	    }
+		cleanBannerGroup();
 	}
 
 	/**
@@ -504,266 +423,52 @@
 	@Override
 	public void onPresenceChanged(PresenceAdapter presence) throws RemoteException {
 	    String from = presence.getFrom();
-	    final boolean hideDisconnected = mSettings.getBoolean(BeemApplication.SHOW_OFFLINE_CONTACTS_KEY, false);
 	    final Contact contact = mRoster.getContact(StringUtils.parseBareAddress(from));
-	    boolean visible = !hideDisconnected || Status.statusOnline(contact.getStatus());
-	    List<String> groups = contact.getGroups();
-	    for (Map.Entry<String, List<Contact>> entry : mContactOnGroup.entrySet()) {
-		List<Contact> contactByGroups = entry.getValue();
-		if (mSelectedGroup.equals(entry.getKey())) {
-		    updateCurrentList(entry.getKey(), contact);
-		    continue;
-		}
-		contactByGroups.remove(contact);
-		if (visible) {
-		    if (groups.contains(entry.getKey())) {
-			contactByGroups.add(contact);
-		    }
-		}
-	    }
-	    if (visible) {
-		addToSpecialList(contact);
-	    }
-	}
-
-	/**
-	 * Add a contact to the special list No Group and All contacts.
-	 * The contact will be added if the list is not the current list otherwise
-	 * the list must be modified in a Handler.
-	 *
-	 * @param contact the contact to add.
-	 */
-	private void addToSpecialList(Contact contact) {
-	    List<String> groups = contact.getGroups();
-	    List<Contact> list = mContactOnGroup.get(getString(R.string.contact_list_all_contact));
-	    if (list != mListContact) {
-		list.add(contact);
-	    }
-	    list = mContactOnGroup.get(getString(R.string.contact_list_no_group));
-	    if (list != mListContact && groups.isEmpty()) {
-		list.add(contact);
-	    }
+	    putContactInList(contact);
 	}
 
-	/**
-	 * Update the current list with the status of contact.
-	 *
-	 * @param listName name of the current list
-	 * @param contact contact to update
-	 */
-	private void updateCurrentList(String listName, final Contact contact) {
-	    final boolean hideDisconnected = mSettings.getBoolean(BeemApplication.SHOW_OFFLINE_CONTACTS_KEY, false);
-	    final List<String> groups = contact.getGroups();
-	    String noGroup = getString(R.string.contact_list_no_group);
-	    String allGroup = getString(R.string.contact_list_all_contact);
-	    final boolean add = ((!hideDisconnected || Status.statusOnline(contact.getStatus())) &&	// must show and
-		(
-		    (listName.equals(noGroup) && groups.isEmpty()) ||			// in no group
-		    groups.contains(listName) ||					// or in current
-		    listName.equals(allGroup)						// or in all
-		));
-	    mHandler.post(new Runnable() {
-		public void run() {
-		    mListContact.remove(contact);
-		    if (add) {
-			mListContact.add(contact);
-		    }
-		    mAdapterContactList.notifyDataSetChanged();
-		}
-	    });
-
-	}
-
-	/**
-	 * Remove old groups on the banner.
-	 * @throws RemoteException if an error occur when communicating with the service
-	 */
-	private void cleanBannerGroup() throws RemoteException {
-	    List<String> rosterGroups = mRoster.getGroupsNames();
-	    List<String> realGroups = mListGroup.subList(1, mListContact.size() - 1);
-	    realGroups.retainAll(rosterGroups);
-	}
-
+	 private void putContactInList(final Contact contact) {
+	    	List<String> groups = contact.getGroups();
+		    for (final String group : groups) {
+		    	runOnUiThread(new Runnable() {
+					
+					@Override
+					public void run() {
+						ContactListAdapter contactListAdapter = getContactListAdapter(group);
+						contactListAdapter.put(contact);					
+					}
+				});
+			}
+		    
+		    runOnUiThread(new Runnable() {
+				
+				@Override
+				public void run() {
+					addToSpecialList(contact);				
+				}
+			});			
+	    }	
     }
-
+    
     /**
-     * Adapter contact list.
+     * Adapter banner list.
      */
-    private class BeemContactList extends BaseAdapter implements Filterable {
-
-	private final ContactFilter mFilter;
+    private class BeemBanner extends BaseAdapter {
 
 	/**
 	 * Constructor.
 	 */
-	public BeemContactList() {
-	    mFilter = new ContactFilter();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public int getCount() {
-	    return mListContact.size();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public Object getItem(int position) {
-	    return mListContact.get(position);
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public long getItemId(int position) {
-	    return mListContact.get(position).hashCode();
-	}
-
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public View getView(int position, View convertView, ViewGroup parent) {
-	    View v = convertView;
-	    if (convertView == null) {
-		v = mInflater.inflate(R.layout.contactlistcontact, null);
-	    }
-	    Contact c = mListContact.get(position);
-	    if (mRoster != null) {
-		try {
-		    c = mRoster.getContact(c.getJID());
-		} catch (RemoteException e) {
-		    e.printStackTrace();
-		}
-	    }
-	    bindView(v, c);
-	    return v;
-	}
-
-	@Override
-	public Filter getFilter() {
-	    return mFilter;
-	}
-
-	/**
-	 * Adapte curContact to the view.
-	 * @param view the row view.
-	 * @param curContact the current contact.
-	 */
-	private void bindView(View view, Contact curContact) {
-	    if (curContact != null) {
-		TextView v = (TextView) view.findViewById(R.id.contactlistpseudo);
-		v.setText(curContact.getName());
-		v = (TextView) view.findViewById(R.id.contactlistmsgperso);
-		v.setText(curContact.getMsgState());
-		ImageView img = (ImageView) view.findViewById(R.id.avatar);
-		String avatarId = curContact.getAvatarId();
-		int contactStatus = curContact.getStatus();
-		Drawable avatar = getAvatarStatusDrawable(avatarId);
-		img.setImageDrawable(avatar);
-		img.setImageLevel(contactStatus);
-	    }
-	}
-
-	/**
-	 * Get a LayerDrawable containing the avatar and the status icon.
-	 * The status icon will change with the level of the drawable.
-	 * @param avatarId the avatar id to retrieve or null to get default
-	 * @return a LayerDrawable
-	 */
-	private Drawable getAvatarStatusDrawable(String avatarId) {
-	    Drawable avatarDrawable = null;
-	    if (avatarId != null) {
-		Uri uri = AvatarProvider.CONTENT_URI.buildUpon().appendPath(avatarId).build();
-		InputStream in = null;
-		try {
-		    try {
-			in = getContentResolver().openInputStream(uri);
-			avatarDrawable = Drawable.createFromStream(in, avatarId);
-		    } finally {
-			if (in != null)
-			    in.close();
-		    }
-		} catch (IOException e) {
-		    Log.w(TAG, "Error while setting the avatar " + avatarId, e);
-		}
-	    }
-	    if (avatarDrawable == null)
-		avatarDrawable = getResources().getDrawable(R.drawable.beem_launcher_icon_silver);
-	    LayerDrawable ld = (LayerDrawable) getResources().getDrawable(R.drawable.avatar_status);
-	    ld.setLayerInset(1, 36, 36, 0, 0);
-	    ld.setDrawableByLayerId(R.id.avatar, avatarDrawable);
-	    return ld;
-	}
-
-	/**
-	 * A Filter which select Contact to display by searching in ther Jid.
-	 */
-	private class ContactFilter extends Filter {
-
-	    /**
-	     * Create a ContactFilter.
-	     */
-	    public ContactFilter() { }
-
-	    @Override
-	    protected Filter.FilterResults performFiltering(CharSequence constraint) {
-		Log.d(TAG, "performFiltering");
-		List<Contact> result = mListContact;
-		if (constraint.length() > 0) {
-		    result = new LinkedList<Contact>();
-		    for (Contact c : mContactOnGroup.get(mSelectedGroup)) {
-			if (c.getJID().contains(constraint))
-			    result.add(c);
-		    }
-		}
-		Filter.FilterResults fr = new Filter.FilterResults();
-		fr.values = result;
-		fr.count = result.size();
-		return fr;
-	    }
-
-	    @Override
-	    protected void publishResults(CharSequence constraint, Filter.FilterResults  results) {
-		Log.d(TAG, "publishResults");
-		List<Contact> contacts = (List<Contact>) results.values;
-		mListContact = contacts;
-		notifyDataSetChanged();
-	    }
-	}
-    }
-
-    /**
-     * Adapter banner list.
-     */
-    private static class BeemBanner extends BaseAdapter {
-	private List<String> mGroups;
-	private LayoutInflater mInflater;
-
-	/**
-	 * Constructor.
-	 * @param inflater the inflater use to create the view for the banner
-	 * @param groups list of the differents groups to adapt
-	 */
-	public BeemBanner(final LayoutInflater inflater, final List<String> groups) {
-	    mGroups = groups;
-	    mInflater = inflater;
+	public BeemBanner() {
 	}
 
 	@Override
 	public int getCount() {
-	    return mGroups.size();
+	    return mListGroup.size();
 	}
 
 	@Override
 	public Object getItem(int position) {
-	    return mGroups.get(position);
+	    return mListGroup.get(position);
 	}
 
 	@Override
@@ -777,7 +482,7 @@
 	    if (convertView == null) {
 		v = mInflater.inflate(R.layout.contactlist_group, null);
 	    }
-	    ((TextView) v).setText(mGroups.get(position));
+	    ((TextView) v).setText(mListGroup.get(position));
 	    return v;
 	}
     }
@@ -801,18 +506,18 @@
 		if (mRoster != null) {
 		    List<String> tmpGroupList = mRoster.getGroupsNames();
 		    Collections.sort(tmpGroupList);
-		    mListGroup.clear();
-		    mListGroup.add(getString(R.string.contact_list_all_contact));
-		    mListGroup.addAll(tmpGroupList);
-		    mListGroup.add(getString(R.string.contact_list_no_group));
+		    cleanBannerGroup();
+		    mListGroup.addAll(1, tmpGroupList);
+		    synchronized (contactListAdapters) {
+		    	for (ContactListAdapter ca : contactListAdapters.values()) {
+		    		ca.clear();
+		    	}
+			}
+		    groupsPagesAdapter.notifyDataSetChanged();
+		    mAdapterBanner.notifyDataSetChanged();
+
 		    assignContactToGroups(mRoster.getContactList(), tmpGroupList);
-		    makeSortedList(mContactOnGroup);
-		    if (!mSettings.getBoolean(BeemApplication.HIDE_GROUPS_KEY, false))
-			showGroups();
-		    else
-			hideGroups();
-		    String group = getString(R.string.contact_list_all_contact);
-		    buildContactList(group);
+		  
 		    mRoster.addRosterListener(mBeemRosterListener);
 		    Log.d(TAG, "add roster listener");
 		    mChatManager = mXmppFacade.getChatManager();
@@ -836,6 +541,7 @@
 	    mListGroup.clear();
 	    mContactOnGroup.clear();
 	    mBinded = false;
+
 	}
 
 	/**
@@ -846,91 +552,23 @@
 	 * @param groupNames list of existing groups
 	 */
 	private void assignContactToGroups(List<Contact> contacts, List<String> groupNames) {
-	    boolean hideDisconnected = mSettings.getBoolean(BeemApplication.SHOW_OFFLINE_CONTACTS_KEY, false);
-	    mContactOnGroup.clear();
-	    List<Contact> all = new LinkedList<Contact>();
-	    List<Contact> noGroups = new LinkedList<Contact>();
-	    for (String group : groupNames) {
-		mContactOnGroup.put(group, new LinkedList<Contact>());
+	    for (Contact c : contacts) {
+	    	addToSpecialList(c);
+
+		List<String> groups = c.getGroups();
+
+		    for (String currentGroup : groups) {
+			ContactListAdapter cl = getContactListAdapter(currentGroup);
+		    cl.put(c);
+		    }
+		
 	    }
-	    for (Contact c : contacts) {
-		if (hideDisconnected && !Status.statusOnline(c.getStatus())) {
-		    continue;
-		}
-		all.add(c);
-		List<String> groups = c.getGroups();
-		if (groups.isEmpty())
-		    noGroups.add(c);
-		else {
-		    for (String currentGroup : groups) {
-			List<Contact> contactsByGroups = mContactOnGroup.get(currentGroup);
-			contactsByGroups.add(c);
-		    }
-		}
-	    }
-	    mContactOnGroup.put(getString(R.string.contact_list_no_group), noGroups);
-	    mContactOnGroup.put(getString(R.string.contact_list_all_contact), all);
 	}
 
-	/**
-	 * Make the List of the map became Insertion sorted list.
-	 *
-	 * @param map the map to convert.
-	 */
-	private void makeSortedList(Map<String, List<Contact>> map) {
-	    for (Map.Entry<String, List<Contact>> entry : map.entrySet()) {
-		List<Contact> l = entry.getValue();
-		entry.setValue(new SortedList<Contact>(l, mComparator));
-	    }
-	}
     }
 
 
 
-
-    /**
-     * Comparator Contact by status and name.
-     */
-    private static class ComparatorContactListByStatusAndName<T> implements Comparator<T> {
-	/**
-	 * Constructor.
-	 */
-	public ComparatorContactListByStatusAndName() {
-	}
-
-	@Override
-	public int compare(T c1, T c2) {
-	    if (((Contact) c1).getStatus() < ((Contact) c2).getStatus()) {
-		return 1;
-	    } else if (((Contact) c1).getStatus() > ((Contact) c2).getStatus()) {
-		return -1;
-	    } else
-		return ((Contact) c1).getName().compareToIgnoreCase(((Contact) c2).getName());
-	}
-    }
-
-    /**
-     * Event simple click on item of the contact list.
-     */
-    private class BeemContactListOnClick implements OnItemClickListener {
-	/**
-	 * Constructor.
-	 */
-	public BeemContactListOnClick() {
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public void onItemClick(AdapterView<?> arg0, View v, int pos, long lpos) {
-	    Contact c = mListContact.get(pos);
-	    Intent i = new Intent(ContactList.this, Chat.class);
-	    i.setData(c.toUri());
-	    startActivity(i);
-	}
-    }
-
     /**
      * Event simple click on middle groupe name.
      */
@@ -944,9 +582,59 @@
 
 	@Override
 	public void onItemClick(AdapterView<?> arg0, View v, int i, long l) {
-	    String group = mListGroup.get(i);
-	    buildContactList(group);
+	    viewPager.setCurrentItem(i, true);
 	}
     }
 
+    private class ListPagerAdapter extends FragmentPagerAdapter {
+
+		public ListPagerAdapter(FragmentManager fm, ViewPager viewPager) {
+			super(fm);
+			viewPager.setAdapter(this);
+		}
+
+		@Override
+		public Fragment getItem(int position) {
+			String group = mListGroup.get(position);
+			ContactListFragment f = ContactListFragment.newInstance(group);
+			f.setListAdapter(getContactListAdapter(group));
+			return f;
+		}
+
+		@Override
+		public int getCount() {
+			return mListGroup.size();
+		}
+    	
+    }
+
+	void doContextMenuAction(int itemId, Contact contact) {
+	    switch (itemId) {
+		case R.id.contact_list_context_menu_call_item:
+		    try {
+			mXmppFacade.call(contact.getJID() + "/psi");
+		    } catch (RemoteException e) {
+			e.printStackTrace();
+		    }
+		    break;
+		case R.id.contact_list_context_menu_userinfo_alias:
+		    Dialog alias = new Alias(ContactList.this, mRoster, contact).create();
+		    alias.show();
+		    break;
+		case R.id.contact_list_context_menu_userinfo_subscription:
+		    Dialog subscription = new ResendSubscription(ContactList.this,
+			mXmppFacade, contact).create();
+		    subscription.show();
+		    break;
+		case R.id.contact_list_context_menu_userinfo_delete:
+		    Dialog delete = new DeleteContact(ContactList.this, mRoster, contact).create();
+		    delete.show();
+		    break;
+		default:
+			Log.w(TAG, "Context menu action not supported" + itemId);
+			break;
+	    }
+
+	}
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/beem/project/beem/ui/ContactListAdapter.java	Wed Feb 29 00:53:20 2012 +0100
@@ -0,0 +1,231 @@
+package com.beem.project.beem.ui;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Comparator;
+import java.util.LinkedList;
+import java.util.List;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+import android.net.Uri;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.Filter;
+import android.widget.Filterable;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.beem.project.beem.R;
+import com.beem.project.beem.providers.AvatarProvider;
+import com.beem.project.beem.service.Contact;
+import com.beem.project.beem.utils.SortedList;
+import com.beem.project.beem.utils.Status;
+
+public class ContactListAdapter extends BaseAdapter implements Filterable {
+	 private static final String TAG = ContactListAdapter.class.getSimpleName();
+	private final ComparatorContactListByStatusAndName<Contact> mComparator =
+				new ComparatorContactListByStatusAndName<Contact>();
+    private List<Contact> mCurrentList;
+    private final List<Contact> allContacts = new SortedList<Contact>(new LinkedList<Contact>(), mComparator);
+    private final List<Contact> onlineContacts = new SortedList<Contact>(new LinkedList<Contact>(), mComparator);
+	private final Filter mFilter = new ContactFilter();
+    private final Context context;
+    private LayoutInflater mInflater;
+
+
+    private boolean showOnlineOnly;
+    
+    public ContactListAdapter(Context c) {
+    	mCurrentList = allContacts;
+    	context = c;
+    	mInflater = (LayoutInflater) c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+    }
+    
+    @Override
+	public int getCount() {
+	    return mCurrentList.size();
+	}
+
+
+	@Override
+	public Object getItem(int position) {
+	    return mCurrentList.get(position);
+	}
+
+
+	@Override
+	public long getItemId(int position) {
+	    return mCurrentList.get(position).hashCode();
+	}
+
+	@Override
+	public View getView(int position, View convertView, ViewGroup parent) {
+	    View v = convertView;
+	    if (convertView == null) {
+		v = mInflater.inflate(R.layout.contactlistcontact, null);
+	    }
+	    Contact c = mCurrentList.get(position);
+	    bindView(v, c);
+	    return v;
+	}
+	
+	public void put(Contact c) {
+		put(c, allContacts);
+		if (Status.statusOnline(c.getStatus()))
+			put(c, onlineContacts);
+		notifyDataSetChanged();
+	}
+	
+	public void remove(Contact c) {
+		allContacts.remove(c);
+		onlineContacts.remove(c);
+		notifyDataSetChanged();
+	}
+	
+	
+	public void clear() {
+		allContacts.clear();
+		onlineContacts.clear();
+		notifyDataSetChanged();
+	}
+	
+	@Override
+	public Filter getFilter() {
+	    return mFilter;
+	}
+	
+	/**
+	 * Adapte curContact to the view.
+	 * @param view the row view.
+	 * @param curContact the current contact.
+	 */
+	private void bindView(View view, Contact curContact) {
+	    if (curContact != null) {
+		TextView v = (TextView) view.findViewById(R.id.contactlistpseudo);
+		v.setText(curContact.getName());
+		v = (TextView) view.findViewById(R.id.contactlistmsgperso);
+		v.setText(curContact.getMsgState());
+		ImageView img = (ImageView) view.findViewById(R.id.avatar);
+		String avatarId = curContact.getAvatarId();
+		int contactStatus = curContact.getStatus();
+		Drawable avatar = getAvatarStatusDrawable(avatarId);
+		img.setImageDrawable(avatar);
+		img.setImageLevel(contactStatus);
+	    }
+	}
+
+	/**
+	 * Get a LayerDrawable containing the avatar and the status icon.
+	 * The status icon will change with the level of the drawable.
+	 * @param avatarId the avatar id to retrieve or null to get default
+	 * @return a LayerDrawable
+	 */
+	private Drawable getAvatarStatusDrawable(String avatarId) {
+	    Drawable avatarDrawable = null;
+	    if (avatarId != null) {
+		Uri uri = AvatarProvider.CONTENT_URI.buildUpon().appendPath(avatarId).build();
+		InputStream in = null;
+		try {
+		    try {
+			in = context.getContentResolver().openInputStream(uri);
+			avatarDrawable = Drawable.createFromStream(in, avatarId);
+		    } finally {
+			if (in != null)
+			    in.close();
+		    }
+		} catch (IOException e) {
+		    Log.w(TAG, "Error while setting the avatar " + avatarId, e);
+		}
+	    }
+	    if (avatarDrawable == null)
+		avatarDrawable = context.getResources().getDrawable(R.drawable.beem_launcher_icon_silver);
+	    LayerDrawable ld = (LayerDrawable) context.getResources().getDrawable(R.drawable.avatar_status);
+	    ld.setLayerInset(1, 36, 36, 0, 0);
+	    ld.setDrawableByLayerId(R.id.avatar, avatarDrawable);
+	    return ld;
+	}
+	
+	private void put(Contact c, List<Contact> list) {
+			list.remove(c);
+			list.add(c);
+	}
+
+	public boolean isOnlineOnly() {
+		return showOnlineOnly;
+	}
+	
+	public void setOnlineOnly(boolean online) {
+		if (online != showOnlineOnly) {
+			showOnlineOnly = online;
+			mCurrentList = showOnlineOnly ? onlineContacts : allContacts;
+			notifyDataSetChanged();
+		}
+	}
+	
+	
+	  /**
+     * Comparator Contact by status and name.
+     */
+    private static class ComparatorContactListByStatusAndName<T> implements Comparator<T> {
+	/**
+	 * Constructor.
+	 */
+	public ComparatorContactListByStatusAndName() {
+	}
+
+	@Override
+	public int compare(T c1, T c2) {
+	    if (((Contact) c1).getStatus() < ((Contact) c2).getStatus()) {
+		return 1;
+	    } else if (((Contact) c1).getStatus() > ((Contact) c2).getStatus()) {
+		return -1;
+	    } else
+		return ((Contact) c1).getName().compareToIgnoreCase(((Contact) c2).getName());
+	}
+    }
+
+	
+	/**
+	 * A Filter which select Contact to display by searching in ther Jid.
+	 */
+	private class ContactFilter extends Filter {
+
+	    /**
+	     * Create a ContactFilter.
+	     */
+	    public ContactFilter() { }
+
+	    @Override
+	    protected Filter.FilterResults performFiltering(CharSequence constraint) {
+		Log.d(TAG, "performFiltering");
+		List<Contact> result = mCurrentList;
+		if (constraint.length() > 0) {
+		    result = new LinkedList<Contact>();
+		    for (Contact c : mCurrentList) {
+			if (c.getJID().contains(constraint))
+			    result.add(c);
+		    }
+		}
+		Filter.FilterResults fr = new Filter.FilterResults();
+		fr.values = result;
+		fr.count = result.size();
+		return fr;
+	    }
+
+	    @Override
+	    protected void publishResults(CharSequence constraint, Filter.FilterResults  results) {
+		Log.d(TAG, "publishResults");
+		List<Contact> contacts = (List<Contact>) results.values;
+		mCurrentList = contacts;
+		notifyDataSetChanged();
+	    }
+	}
+    
+	
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/beem/project/beem/ui/ContactListFragment.java	Wed Feb 29 00:53:20 2012 +0100
@@ -0,0 +1,145 @@
+package com.beem.project.beem.ui;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.support.v4.app.ListFragment;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.AdapterView.AdapterContextMenuInfo;
+import android.widget.Filter;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+
+import com.beem.project.beem.R;
+import com.beem.project.beem.service.Contact;
+import com.beem.project.beem.ui.dialogs.builders.Alias;
+import com.beem.project.beem.ui.dialogs.builders.DeleteContact;
+import com.beem.project.beem.ui.dialogs.builders.ResendSubscription;
+
+public class ContactListFragment extends ListFragment {
+	private String group;
+	private ContactList hostActivity;
+	private Contact mSelectedContact;
+	
+	public static ContactListFragment newInstance(String group) {
+		ContactListFragment f = new ContactListFragment();
+		Bundle b = new Bundle();
+		b.putString("group", group);
+		f.setArguments(b);
+		return f;
+	}
+	
+	@Override
+	public void onCreate(Bundle savedInstanceState) {
+		super.onCreate(savedInstanceState);
+		parseArguments();
+	}
+	
+	@Override
+	public void onAttach(Activity activity) {
+		super.onAttach(activity);
+		hostActivity = (ContactList) activity;
+	}
+	
+	@Override
+	public void onActivityCreated(Bundle savedInstanceState) {
+		super.onActivityCreated(savedInstanceState);
+		ListAdapter adapter = hostActivity.getContactListAdapter(group);
+		setListAdapter(adapter);
+		registerForContextMenu(getListView());
+	}
+	
+	@Override
+	public void onListItemClick(ListView l, View v, int position, long id) {
+		ContactListAdapter a  = (ContactListAdapter) getListAdapter();
+		Contact c = (Contact) a.getItem(position);
+	    Intent i = new Intent(getActivity(), Chat.class);
+	    i.setData(c.toUri());
+	    startActivity(i);
+	}
+	
+	
+	
+    @Override
+    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
+	super.onCreateContextMenu(menu, v, menuInfo);
+	MenuInflater inflater =  hostActivity.getMenuInflater();
+	inflater.inflate(R.menu.contactlist_context, menu);
+	AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
+	mSelectedContact = (Contact) getListAdapter().getItem(info.position);
+	menu.setHeaderTitle(mSelectedContact.getJID());
+    }
+
+	private void parseArguments() {
+		Bundle b = getArguments();
+		if (b == null)
+			return;
+		group = b.getString("group");
+	}
+	
+	   @Override
+	    public boolean onContextItemSelected(MenuItem item) {
+		Intent in;
+		boolean result = false;
+		if (mSelectedContact != null) {
+		    switch (item.getItemId()) {
+			case R.id.contact_list_context_menu_chat_item:
+			    List<String> res = mSelectedContact.getMRes();
+			    if (res.isEmpty()) {
+				break;
+			    }
+			    for (String resv : res) {
+				in = new Intent(hostActivity, Chat.class);
+				in.setData(mSelectedContact.toUri(resv));
+				item.getSubMenu().add(resv).setIntent(in);
+			    }
+			    result = true;
+			    break;
+			case R.id.contact_list_context_menu_call_item:
+				hostActivity.doContextMenuAction(item.getItemId(), mSelectedContact);
+				break;
+			case R.id.contact_list_context_menu_user_info:
+			    item.getSubMenu().setHeaderTitle(mSelectedContact.getJID());
+			    result = true;
+			    break;
+			case R.id.contact_list_context_menu_userinfo_alias:
+				hostActivity.doContextMenuAction(item.getItemId(), mSelectedContact);
+			    result = true;
+			    break;
+			case R.id.contact_list_context_menu_userinfo_group:
+			    in = new Intent(hostActivity, GroupList.class);
+			    in.putExtra("contact", mSelectedContact);
+			    startActivity(in);
+			    result = true;
+			    break;
+			case R.id.contact_list_context_menu_userinfo_subscription:
+				hostActivity.doContextMenuAction(item.getItemId(), mSelectedContact);
+			    result = true;
+			    break;
+			case R.id.contact_list_context_menu_userinfo_block:
+			    result = true;
+			    break;
+			case R.id.contact_list_context_menu_userinfo_delete:
+				hostActivity.doContextMenuAction(item.getItemId(), mSelectedContact);
+			    result = true;
+			    break;
+			default:
+			    result = super.onContextItemSelected(item);
+			    break;
+		    }
+		    return result;
+		}
+		return super.onContextItemSelected(item);
+	    }
+	
+}