src/com/beem/project/beem/ui/ContactList.java
changeset 760 97451b0f4f09
parent 759 5f7bbb0c2731
child 763 e6a235546a90
equal deleted inserted replaced
759:5f7bbb0c2731 760:97451b0f4f09
    48 import java.util.Comparator;
    48 import java.util.Comparator;
    49 import java.util.HashMap;
    49 import java.util.HashMap;
    50 import java.util.List;
    50 import java.util.List;
    51 import java.util.Map;
    51 import java.util.Map;
    52 import java.util.Map.Entry;
    52 import java.util.Map.Entry;
    53 import java.util.Iterator;
       
    54 
    53 
    55 import org.jivesoftware.smack.util.StringUtils;
    54 import org.jivesoftware.smack.util.StringUtils;
    56 
    55 
    57 import android.app.Activity;
    56 import android.app.Activity;
    58 import android.app.Dialog;
    57 import android.app.Dialog;
    94 import com.beem.project.beem.ui.dialogs.builders.Alias;
    93 import com.beem.project.beem.ui.dialogs.builders.Alias;
    95 import com.beem.project.beem.ui.dialogs.builders.DeleteContact;
    94 import com.beem.project.beem.ui.dialogs.builders.DeleteContact;
    96 import com.beem.project.beem.ui.dialogs.builders.ResendSubscription;
    95 import com.beem.project.beem.ui.dialogs.builders.ResendSubscription;
    97 import com.beem.project.beem.utils.BeemBroadcastReceiver;
    96 import com.beem.project.beem.utils.BeemBroadcastReceiver;
    98 import com.beem.project.beem.utils.Status;
    97 import com.beem.project.beem.utils.Status;
       
    98 import com.beem.project.beem.utils.SortedList;
    99 
    99 
   100 /**
   100 /**
   101  * The contact list activity displays the roster of the user.
   101  * The contact list activity displays the roster of the user.
   102  */
   102  */
   103 public class ContactList extends Activity {
   103 public class ContactList extends Activity {
   105     private static final Intent SERVICE_INTENT = new Intent();
   105     private static final Intent SERVICE_INTENT = new Intent();
   106     static {
   106     static {
   107 	SERVICE_INTENT.setComponent(new ComponentName("com.beem.project.beem", "com.beem.project.beem.BeemService"));
   107 	SERVICE_INTENT.setComponent(new ComponentName("com.beem.project.beem", "com.beem.project.beem.BeemService"));
   108     }
   108     }
   109 
   109 
   110     private static final int REQUEST_CODE = 1;
       
   111     private static final String SETTINGS_HIDDEN_CONTACT = "settings_key_hidden_contact";
   110     private static final String SETTINGS_HIDDEN_CONTACT = "settings_key_hidden_contact";
   112     private static final String TAG = "ContactList";
   111     private static final String TAG = "ContactList";
   113     private final BeemContactList mAdapterContactList = new BeemContactList();
   112     private final BeemContactList mAdapterContactList = new BeemContactList();
   114     private final List<String> mListGroup = new ArrayList<String>();
   113     private final List<String> mListGroup = new ArrayList<String>();
       
   114 
       
   115     /** Map containing a list of the different contacts of a given group.
       
   116      * Each list is a @{link SortedList} so there is no need to sort it again.
       
   117      * */
   115     private final Map<String, List<Contact>> mContactOnGroup = new HashMap<String, List<Contact>>();
   118     private final Map<String, List<Contact>> mContactOnGroup = new HashMap<String, List<Contact>>();
   116     private final BeemContactListOnClick mOnContactClick = new BeemContactListOnClick();
   119     private final BeemContactListOnClick mOnContactClick = new BeemContactListOnClick();
   117     private final Handler mHandler = new Handler();
   120     private final Handler mHandler = new Handler();
   118     private final ServiceConnection mServConn = new BeemServiceConnection();
   121     private final ServiceConnection mServConn = new BeemServiceConnection();
   119     private final BeemBroadcastReceiver mReceiver = new BeemBroadcastReceiver();
   122     private final BeemBroadcastReceiver mReceiver = new BeemBroadcastReceiver();
   131 
   134 
   132     /**
   135     /**
   133      * Constructor.
   136      * Constructor.
   134      */
   137      */
   135     public ContactList() {
   138     public ContactList() {
   136 
       
   137     }
   139     }
   138 
   140 
   139     /**
   141     /**
   140      * Callback for menu creation.
   142      * Callback for menu creation.
   141      * @param menu the menu created
   143      * @param menu the menu created
   224 		    in.putExtra("contact", mSelectedContact);
   226 		    in.putExtra("contact", mSelectedContact);
   225 		    startActivity(in);
   227 		    startActivity(in);
   226 		    result = true;
   228 		    result = true;
   227 		    break;
   229 		    break;
   228 		case R.id.contact_list_context_menu_userinfo_subscription:
   230 		case R.id.contact_list_context_menu_userinfo_subscription:
   229 		    Dialog subscription = new ResendSubscription(ContactList.this, mXmppFacade, mSelectedContact).create();
   231 		    Dialog subscription = new ResendSubscription(ContactList.this,
       
   232 			    mXmppFacade, mSelectedContact).create();
   230 		    subscription.show();
   233 		    subscription.show();
   231 		    result = true;
   234 		    result = true;
   232 		    break;
   235 		    break;
   233 		case R.id.contact_list_context_menu_userinfo_block:
   236 		case R.id.contact_list_context_menu_userinfo_block:
   234 		    result = true;
   237 		    result = true;
   298 	this.unregisterReceiver(mReceiver);
   301 	this.unregisterReceiver(mReceiver);
   299 	Log.e(TAG, "onDestroy activity");
   302 	Log.e(TAG, "onDestroy activity");
   300     }
   303     }
   301 
   304 
   302     /**
   305     /**
       
   306      * Build and display the contact list.
       
   307      * @param group name of the contact list.
       
   308      */
       
   309     private void buildContactList(String group) {
       
   310 	mListContact = mContactOnGroup.get(group);
       
   311 	Log.d(TAG, "buildContactList for group " + group);
       
   312 	mAdapterContactList.notifyDataSetChanged();
       
   313     }
       
   314 
       
   315     /**
       
   316      * Show the groups view.
       
   317      */
       
   318     private void showGroups() {
       
   319 
       
   320 	ViewStub stub = (ViewStub) findViewById(R.id.contactlist_stub);
       
   321 	if (stub != null) {
       
   322 	    View v = stub.inflate();
       
   323 	    Gallery g = (Gallery) v.findViewById(R.id.contactlist_banner);
       
   324 	    g.setOnItemClickListener(new OnItemClickGroupName());
       
   325 	    g.setAdapter(mAdapterBanner);
       
   326 	    g.setSelection(0);
       
   327 	} else {
       
   328 	    ((LinearLayout) findViewById(R.id.contactlist_groupstub)).setVisibility(View.VISIBLE);
       
   329 	    Gallery g = (Gallery) findViewById(R.id.contactlist_banner);
       
   330 	    g.setSelection(0);
       
   331 	}
       
   332     }
       
   333 
       
   334     /**
       
   335      * Hide the groups view.
       
   336      */
       
   337     private void hideGroups() {
       
   338 	View v = findViewById(R.id.contactlist_groupstub);
       
   339 	if (v != null)
       
   340 	    v.setVisibility(View.GONE);
       
   341     }
       
   342 
       
   343     /**
       
   344      * Listener on service event.
       
   345      */
       
   346     private class BeemRosterListener extends IBeemRosterListener.Stub {
       
   347 	/**
       
   348 	 * Constructor.
       
   349 	 */
       
   350 	public BeemRosterListener() {
       
   351 	}
       
   352 
       
   353 	/**
       
   354 	 * {@inheritDoc}
       
   355 	 * Simple stategy to handle the onEntriesAdded event.
       
   356 	 * if contact has to be shown :
       
   357 	 * <ul>
       
   358 	 * <li> add him to his groups</li>
       
   359 	 * <li> add him to the specials groups</>
       
   360 	 * </ul>
       
   361 	 */
       
   362 	@Override
       
   363 	public void onEntriesAdded(final List<String> addresses) throws RemoteException {
       
   364 	    final boolean hideDisconnected = mSettings.getBoolean(SETTINGS_HIDDEN_CONTACT, false);
       
   365 	    for (String newName : addresses) {
       
   366 		Contact contact = mRoster.getContact(newName);
       
   367 		boolean visible = !hideDisconnected || Status.statusOnline(contact.getStatus());
       
   368 		List<String> groups = contact.getGroups();
       
   369 		if (visible) {
       
   370 		    for (String group : groups) {
       
   371 			if (!mListGroup.contains(group)) {
       
   372 			    mListGroup.add(mListGroup.size() - 1, group);
       
   373 			    List<Contact> tmplist = new SortedList<Contact>(new LinkedList<Contact>(), mComparator);
       
   374 			    mContactOnGroup.put(group, tmplist);
       
   375 			}
       
   376 			List<Contact> contactByGroups = mContactOnGroup.get(group);
       
   377 			if (contactByGroups == mListContact) {
       
   378 			    updateCurrentList(group, contact);
       
   379 			    continue;
       
   380 			}
       
   381 			contactByGroups.add(contact);
       
   382 		    }
       
   383 
       
   384 		    // add the contact to all and no groups
       
   385 		    addToSpecialList(contact);
       
   386 		}
       
   387 	    }
       
   388 	}
       
   389 
       
   390 	/**
       
   391 	 * {@inheritDoc}
       
   392 	 * Simple stategy to handle the onEntriesDeleted event.
       
   393 	 * <ul>
       
   394 	 * <li> Remove the contact from all groups</li>
       
   395 	 * </ul>
       
   396 	 */
       
   397 	@Override
       
   398 	public void onEntriesDeleted(final List<String> addresses) throws RemoteException {
       
   399 	    Log.d(TAG, "onEntries deleted " + addresses);
       
   400 	    for (String cToDelete : addresses) {
       
   401 		Contact contact = new Contact(cToDelete);
       
   402 		for (Map.Entry<String, List<Contact>> entry : mContactOnGroup.entrySet()) {
       
   403 		    List<Contact> contactByGroups = entry.getValue();
       
   404 		    if (contactByGroups == mListContact) {
       
   405 			updateCurrentList(entry.getKey(), contact);
       
   406 			continue;
       
   407 		    }
       
   408 		    contactByGroups.remove(contact);
       
   409 		}
       
   410 		cleanBannerGroup();
       
   411 	    }
       
   412 
       
   413 	    mHandler.post(new Runnable() {
       
   414 		public void run() {
       
   415 		    mListContact = mContactOnGroup.get(getString(R.string.contact_list_all_contact));
       
   416 		    mAdapterContactList.notifyDataSetChanged();
       
   417 		}
       
   418 	    });
       
   419 
       
   420 	}
       
   421 
       
   422 	/**
       
   423 	 * {@inheritDoc}
       
   424 	 * Simple stategy to handle the onEntriesUpdated event.
       
   425 	 * <ul>
       
   426 	 * <li> Remove the contact from all groups</li>
       
   427 	 * <li> if contact has to be shown add it to his groups</li>
       
   428 	 * <li> if contact has to be shown add it to the specials groups</li>
       
   429 	 * </ul>
       
   430 	 */
       
   431 	@Override
       
   432 	public void onEntriesUpdated(final List<String> addresses) throws RemoteException {
       
   433 	    final boolean hideDisconnected = mSettings.getBoolean(SETTINGS_HIDDEN_CONTACT, false);
       
   434 	    for (String adr : addresses) {
       
   435 		Contact contact = mRoster.getContact(adr);
       
   436 		boolean visible = !hideDisconnected || Status.statusOnline(contact.getStatus());
       
   437 		List<String> groups = contact.getGroups();
       
   438 		for (Map.Entry<String, List<Contact>> entry : mContactOnGroup.entrySet()) {
       
   439 		    List<Contact> contactByGroups = entry.getValue();
       
   440 		    if (contactByGroups == mListContact) {
       
   441 			updateCurrentList(entry.getKey(), contact);
       
   442 			continue;
       
   443 		    }
       
   444 		    contactByGroups.remove(contact);
       
   445 		    if (visible) {
       
   446 			for (String group : groups) {
       
   447 			    if (!mListGroup.contains(group)) {
       
   448 				mListGroup.add(mListGroup.size() - 1, group);
       
   449 				List<Contact> tmplist = new SortedList<Contact>(
       
   450 					new LinkedList<Contact>(), mComparator);
       
   451 				mContactOnGroup.put(group, tmplist);
       
   452 			    }
       
   453 			    mContactOnGroup.get(group).remove(contact);
       
   454 			}
       
   455 		    }
       
   456 
       
   457 		}
       
   458 
       
   459 		// add the contact to all and no groups
       
   460 		if (visible) {
       
   461 		    addToSpecialList(contact);
       
   462 		}
       
   463 	    }
       
   464 	    cleanBannerGroup();
       
   465 	}
       
   466 
       
   467 	/**
       
   468 	 * {@inheritDoc}
       
   469 	 * Simple stategy to handle the onPresenceChanged event.
       
   470 	 * <ul>
       
   471 	 * <li> Remove the contact from all groups</li>
       
   472 	 * <li> if contact has to be shown add it to his groups</li>
       
   473 	 * <li> if contact has to be shown add it to the specials groups</li>
       
   474 	 * </ul>
       
   475 	 */
       
   476 	@Override
       
   477 	public void onPresenceChanged(PresenceAdapter presence) throws RemoteException {
       
   478 	    Log.d(TAG, "presence");
       
   479 	    String from = presence.getFrom();
       
   480 	    final boolean hideDisconnected = mSettings.getBoolean(SETTINGS_HIDDEN_CONTACT, false);
       
   481 	    final Contact contact = mRoster.getContact(StringUtils.parseBareAddress(from));
       
   482 	    boolean visible = !hideDisconnected || Status.statusOnline(contact.getStatus());
       
   483 	    List<String> groups = contact.getGroups();
       
   484 	    for (Map.Entry<String, List<Contact>> entry : mContactOnGroup.entrySet()) {
       
   485 		List<Contact> contactByGroups = entry.getValue();
       
   486 		if (contactByGroups == mListContact) {
       
   487 		    updateCurrentList(entry.getKey(), contact);
       
   488 		    continue;
       
   489 		}
       
   490 		contactByGroups.remove(contact);
       
   491 		if (visible) {
       
   492 		    if (groups.contains(entry.getKey())) {
       
   493 			contactByGroups.add(contact);
       
   494 		    }
       
   495 		}
       
   496 	    }
       
   497 	    if (visible) {
       
   498 		addToSpecialList(contact);
       
   499 	    }
       
   500 	}
       
   501 
       
   502 	/**
       
   503 	 * Add a contact to the special list No Group and All contacts.
       
   504 	 * The contact will be added if the list is not the current list otherwise
       
   505 	 * the list must be modified in a Handler.
       
   506 	 *
       
   507 	 * @param contact the contact to add.
       
   508 	 */
       
   509 	private void addToSpecialList(Contact contact) {
       
   510 	    List<String> groups = contact.getGroups();
       
   511 	    List<Contact> list = mContactOnGroup.get(getString(R.string.contact_list_all_contact));
       
   512 	    if (list != mListContact) {
       
   513 		list.add(contact);
       
   514 	    }
       
   515 	    list = mContactOnGroup.get(getString(R.string.contact_list_no_group));
       
   516 	    if (list != mListContact && groups.isEmpty()) {
       
   517 		list.add(contact);
       
   518 	    }
       
   519 	}
       
   520 
       
   521 	/**
       
   522 	 * Update the current list with the status of contact.
       
   523 	 *
       
   524 	 * @param listName name of the current list
       
   525 	 * @param contact contact to update
       
   526 	 */
       
   527 	private void updateCurrentList(String listName, final Contact contact) {
       
   528 	    final boolean hideDisconnected = mSettings.getBoolean(SETTINGS_HIDDEN_CONTACT, false);
       
   529 	    final List<String> groups = contact.getGroups();
       
   530 	    String noGroup = getString(R.string.contact_list_no_group);
       
   531 	    String allGroup = getString(R.string.contact_list_all_contact);
       
   532 	    final boolean add = ((!hideDisconnected || Status.statusOnline(contact.getStatus())) &&	// must show and
       
   533 		    (
       
   534 		     (listName.equals(noGroup) && groups.isEmpty()) ||			// in no group
       
   535 		     groups.contains(listName) ||					// or in current
       
   536 		     listName.equals(allGroup)						// or in all
       
   537 		    ));
       
   538 	    mHandler.post(new Runnable() {
       
   539 		public void run() {
       
   540 		    mListContact.remove(contact);
       
   541 		    if (add) {
       
   542 			mListContact.add(contact);
       
   543 		    }
       
   544 		    mAdapterContactList.notifyDataSetChanged();
       
   545 		}
       
   546 	    });
       
   547 
       
   548 	}
       
   549 
       
   550 	/**
       
   551 	 * Remove old groups on the banner.
       
   552 	 * @throws RemoteException if an error occur when communicating with the service
       
   553 	 */
       
   554 	private void cleanBannerGroup() throws RemoteException {
       
   555 	    List<String> rosterGroups = mRoster.getGroupsNames();
       
   556 	    List<String> realGroups = mListGroup.subList(1, mListContact.size() - 1);
       
   557 	    realGroups.retainAll(rosterGroups);
       
   558 	}
       
   559 
       
   560     }
       
   561 
       
   562     /**
       
   563      * Adapter contact list.
       
   564      */
       
   565     private class BeemContactList extends BaseAdapter {
       
   566 
       
   567 	/**
       
   568 	 * Constructor.
       
   569 	 */
       
   570 	public BeemContactList() {
       
   571 	}
       
   572 
       
   573 	/**
       
   574 	 * {@inheritDoc}
       
   575 	 */
       
   576 	@Override
       
   577 	public int getCount() {
       
   578 	    return mListContact.size();
       
   579 	}
       
   580 
       
   581 	/**
       
   582 	 * {@inheritDoc}
       
   583 	 */
       
   584 	@Override
       
   585 	public Object getItem(int position) {
       
   586 	    return mListContact.get(position);
       
   587 	}
       
   588 
       
   589 	/**
       
   590 	 * {@inheritDoc}
       
   591 	 */
       
   592 	@Override
       
   593 	public long getItemId(int position) {
       
   594 	    return position;
       
   595 	}
       
   596 
       
   597 	/**
       
   598 	 * {@inheritDoc}
       
   599 	 */
       
   600 	@Override
       
   601 	public View getView(int position, View convertView, ViewGroup parent) {
       
   602 	    View v = convertView;
       
   603 	    if (convertView == null) {
       
   604 		v = mInflater.inflate(R.layout.contactlistcontact, null);
       
   605 	    }
       
   606 	    Contact c = mListContact.get(position);
       
   607 	    if (mRoster != null) {
       
   608 		try {
       
   609 		    c = mRoster.getContact(c.getJID());
       
   610 		} catch (RemoteException e) {
       
   611 		    e.printStackTrace();
       
   612 		}
       
   613 	    }
       
   614 	    bindView(v, c);
       
   615 	    return v;
       
   616 	}
       
   617 
       
   618 	/**
       
   619 	 * Adapte curContact to the view.
       
   620 	 * @param view the row view.
       
   621 	 * @param curContact the current contact.
       
   622 	 */
       
   623 	private void bindView(View view, Contact curContact) {
       
   624 
       
   625 	    if (curContact != null) {
       
   626 		TextView v = (TextView) view.findViewById(R.id.contactlistpseudo);
       
   627 		LevelListDrawable mStatusDrawable = (LevelListDrawable) getResources()
       
   628 		    .getDrawable(R.drawable.status_icon);
       
   629 		mStatusDrawable.setLevel(curContact.getStatus());
       
   630 		v.setCompoundDrawablesWithIntrinsicBounds(mStatusDrawable, null, null, null);
       
   631 		v.setText(curContact.getName());
       
   632 		v = (TextView) view.findViewById(R.id.contactlistmsgperso);
       
   633 		v.setText(curContact.getMsgState());
       
   634 	    }
       
   635 	}
       
   636     }
       
   637 
       
   638     /**
       
   639      * Adapter banner list.
       
   640      */
       
   641     private static class BeemBanner extends BaseAdapter {
       
   642 	private List<String> mGroups;
       
   643 	private LayoutInflater mInflater;
       
   644 
       
   645 	/**
       
   646 	 * Constructor.
       
   647 	 * @param inflater the inflater use to create the view for the banner
       
   648 	 * @param groups list of the differents groups to adapt
       
   649 	 */
       
   650 	public BeemBanner(final LayoutInflater inflater, final List<String> groups) {
       
   651 	    mGroups = groups;
       
   652 	    mInflater = inflater;
       
   653 	}
       
   654 
       
   655 	@Override
       
   656 	public int getCount() {
       
   657 	    return mGroups.size();
       
   658 	}
       
   659 
       
   660 	@Override
       
   661 	public Object getItem(int position) {
       
   662 	    return mGroups.get(position);
       
   663 	}
       
   664 
       
   665 	@Override
       
   666 	public long getItemId(int position) {
       
   667 	    return position;
       
   668 	}
       
   669 
       
   670 	@Override
       
   671 	public View getView(int position, View convertView, ViewGroup parent) {
       
   672 	    View v = convertView;
       
   673 	    if (convertView == null) {
       
   674 		v = mInflater.inflate(R.layout.contactlist_group, null);
       
   675 	    }
       
   676 	    ((TextView) v).setText(mGroups.get(position));
       
   677 	    return v;
       
   678 	}
       
   679     }
       
   680 
       
   681     /**
       
   682      * The service connection used to connect to the Beem service.
       
   683      */
       
   684     private class BeemServiceConnection implements ServiceConnection {
       
   685 
       
   686 	/**
       
   687 	 * Constructor.
       
   688 	 */
       
   689 	public BeemServiceConnection() {
       
   690 	}
       
   691 
       
   692 	@Override
       
   693 	public void onServiceConnected(ComponentName name, IBinder service) {
       
   694 	    mXmppFacade = IXmppFacade.Stub.asInterface(service);
       
   695 	    try {
       
   696 		mRoster = mXmppFacade.getRoster();
       
   697 		if (mRoster != null) {
       
   698 		    List<Contact> tmpContactList = mRoster.getContactList();
       
   699 		    List<String> tmpGroupList = mRoster.getGroupsNames();
       
   700 		    Collections.sort(tmpGroupList);
       
   701 		    mListGroup.clear();
       
   702 		    mListGroup.add(getString(R.string.contact_list_all_contact));
       
   703 		    mListGroup.addAll(tmpGroupList);
       
   704 		    mListGroup.add(getString(R.string.contact_list_no_group));
       
   705 		    assignContactToGroups(mRoster.getContactList(), tmpGroupList);
       
   706 		    makeSortedList(mContactOnGroup);
       
   707 		    if (!mSettings.getBoolean("settings_key_hide_groups", false))
       
   708 			showGroups();
       
   709 		    else
       
   710 			hideGroups();
       
   711 		    String group = getString(R.string.contact_list_all_contact);
       
   712 		    buildContactList(group);
       
   713 		    mRoster.addRosterListener(mBeemRosterListener);
       
   714 		    Log.d(TAG, "add rester listneer");
       
   715 		}
       
   716 	    } catch (RemoteException e) {
       
   717 		e.printStackTrace();
       
   718 	    }
       
   719 	}
       
   720 
       
   721 	@Override
       
   722 	public void onServiceDisconnected(ComponentName name) {
       
   723 	    try {
       
   724 		mRoster.removeRosterListener(mBeemRosterListener);
       
   725 	    } catch (RemoteException e) {
       
   726 		e.printStackTrace();
       
   727 	    }
       
   728 	    mXmppFacade = null;
       
   729 	    mRoster = null;
       
   730 	    mListContact.clear();
       
   731 	    mListGroup.clear();
       
   732 	    mContactOnGroup.clear();
       
   733 	    mBinded = false;
       
   734 	}
       
   735 
       
   736 	/**
       
   737 	 * Assign the differents contact to their groups.
       
   738 	 * This methods will fill the mContactOnGroup map.
       
   739 	 *
       
   740 	 * @param contacts list of contacts
       
   741 	 * @param groupNames list of existing groups
       
   742 	 */
       
   743 	private void assignContactToGroups(List<Contact> contacts, List<String> groupNames) {
       
   744 	    boolean hideDisconnected = mSettings.getBoolean(SETTINGS_HIDDEN_CONTACT, false);
       
   745 	    mContactOnGroup.clear();
       
   746 	    List<Contact> all = new LinkedList<Contact>();
       
   747 	    List<Contact> noGroups = new LinkedList<Contact>();
       
   748 	    for (String group : groupNames) {
       
   749 		mContactOnGroup.put(group, new LinkedList<Contact>());
       
   750 	    }
       
   751 	    for (Contact c : contacts) {
       
   752 		if (hideDisconnected && !Status.statusOnline(c.getStatus())) {
       
   753 		    continue;
       
   754 		}
       
   755 		all.add(c);
       
   756 		List<String> groups = c.getGroups();
       
   757 		if (groups.isEmpty())
       
   758 		    noGroups.add(c);
       
   759 		else {
       
   760 		    for (String currentGroup : groups) {
       
   761 			List<Contact> contactsByGroups = mContactOnGroup.get(currentGroup);
       
   762 			contactsByGroups.add(c);
       
   763 		    }
       
   764 		}
       
   765 	    }
       
   766 	    mContactOnGroup.put(getString(R.string.contact_list_no_group), noGroups);
       
   767 	    mContactOnGroup.put(getString(R.string.contact_list_all_contact), all);
       
   768 	}
       
   769 
       
   770 	/**
       
   771 	 * Make the List of the map became Insertion sorted list.
       
   772 	 *
       
   773 	 * @param map the map to convert.
       
   774 	 */
       
   775 	private void makeSortedList(Map<String, List<Contact>> map) {
       
   776 	    for (Map.Entry<String, List<Contact>> entry : map.entrySet()) {
       
   777 		List<Contact> l = entry.getValue();
       
   778 		entry.setValue(new SortedList<Contact>(l, mComparator));
       
   779 	    }
       
   780 	}
       
   781     }
       
   782 
       
   783 
       
   784 
       
   785 
       
   786     /**
   303      * Comparator Contact by status and name.
   787      * Comparator Contact by status and name.
   304      */
   788      */
   305     private static class ComparatorContactListByStatusAndName<T> implements Comparator<T> {
   789     private static class ComparatorContactListByStatusAndName<T> implements Comparator<T> {
   306 	/**
   790 	/**
   307 	 * Constructor.
   791 	 * Constructor.
   319 		return ((Contact) c1).getName().compareToIgnoreCase(((Contact) c2).getName());
   803 		return ((Contact) c1).getName().compareToIgnoreCase(((Contact) c2).getName());
   320 	}
   804 	}
   321     }
   805     }
   322 
   806 
   323     /**
   807     /**
   324      * Contact List construction.
       
   325      */
       
   326     private void buildContactList(String group) {
       
   327 	mListContact = mContactOnGroup.get(group);
       
   328 	Log.d(TAG, "buildContactList for group " + group);
       
   329 	sortBeemContactList();
       
   330     }
       
   331 
       
   332     /**
       
   333      * showGroups.
       
   334      */
       
   335     private void showGroups() {
       
   336 
       
   337 	ViewStub stub = (ViewStub) findViewById(R.id.contactlist_stub);
       
   338 	if (stub != null) {
       
   339 	    View v = stub.inflate();
       
   340 	    Gallery g = (Gallery) v.findViewById(R.id.contactlist_banner);
       
   341 	    g.setOnItemClickListener(new OnItemClickGroupName());
       
   342 	    g.setAdapter(mAdapterBanner);
       
   343 	} else
       
   344 	    ((LinearLayout) findViewById(R.id.contactlist_groupstub)).setVisibility(View.VISIBLE);
       
   345     }
       
   346 
       
   347     /**
       
   348      * Event simple click on item of the contact list.
   808      * Event simple click on item of the contact list.
   349      */
   809      */
   350     private class BeemContactListOnClick implements OnItemClickListener {
   810     private class BeemContactListOnClick implements OnItemClickListener {
   351 	/**
   811 	/**
   352 	 * Constructor.
   812 	 * Constructor.
   382 	    String group = mListGroup.get(i);
   842 	    String group = mListGroup.get(i);
   383 	    buildContactList(group);
   843 	    buildContactList(group);
   384 	}
   844 	}
   385     }
   845     }
   386 
   846 
   387     /**
       
   388      * Sort the contact list.
       
   389      */
       
   390     private void sortBeemContactList() {
       
   391 	Log.d(TAG, "Sort ");
       
   392 	Collections.sort(mListContact, mComparator);
       
   393 	mAdapterContactList.notifyDataSetChanged();
       
   394     }
       
   395 
       
   396     /**
       
   397      * Listener on service event.
       
   398      */
       
   399     private class BeemRosterListener extends IBeemRosterListener.Stub {
       
   400 	/**
       
   401 	 * Constructor.
       
   402 	 */
       
   403 	public BeemRosterListener() {
       
   404 	}
       
   405 
       
   406 	/**
       
   407 	 * Refresh the contact list.
       
   408 	 */
       
   409 	private class RunnableChange implements Runnable {
       
   410 	    /**
       
   411 	     * Constructor.
       
   412 	     */
       
   413 	    public RunnableChange() {
       
   414 
       
   415 	    }
       
   416 
       
   417 	    /**
       
   418 	     * {@inheritDoc}
       
   419 	     */
       
   420 	    @Override
       
   421 	    public void run() {
       
   422 		sortBeemContactList();
       
   423 		mAdapterContactList.notifyDataSetChanged();
       
   424 		mAdapterBanner.notifyDataSetChanged();
       
   425 	    }
       
   426 	}
       
   427 
       
   428 	/**
       
   429 	 * {@inheritDoc}
       
   430 	 */
       
   431 	@Override
       
   432 	public void onEntriesAdded(List<String> addresses) throws RemoteException {
       
   433 	    boolean hideDisconnected = mSettings.getBoolean(SETTINGS_HIDDEN_CONTACT, false);
       
   434 	    for (String newName : addresses) {
       
   435 		Contact c = mRoster.getContact(newName);
       
   436 		if (!hideDisconnected || Status.statusOnline(c.getStatus())) {
       
   437 		    mContactOnGroup.get(getString(R.string.contact_list_all_contact)).add(c);
       
   438 		    if (c.getGroups().size() == 0)
       
   439 			mContactOnGroup.get(getString(R.string.contact_list_no_group)).add(c);
       
   440 		    for (String group : c.getGroups()) {
       
   441 			if (!mListGroup.contains(group)) {
       
   442 			    mListGroup.add(mListGroup.size() - 1, group);
       
   443 			    List<Contact> tmplist = new LinkedList<Contact>();
       
   444 			    mContactOnGroup.put(group, tmplist);
       
   445 			}
       
   446 			mContactOnGroup.get(group).add(c);
       
   447 		    }
       
   448 		}
       
   449 	    }
       
   450 	    mHandler.post(new RunnableChange());
       
   451 	}
       
   452 
       
   453 	/**
       
   454 	 * {@inheritDoc}
       
   455 	 */
       
   456 	@Override
       
   457 	public void onEntriesDeleted(List<String> addresses) throws RemoteException {
       
   458 	    Log.d(TAG, "onEntries deleted " + addresses);
       
   459 	    for (String cToDelete : addresses) {
       
   460 		Contact contact = mRoster.getContact(cToDelete);
       
   461 		for (List<Contact> contactByGroups : mContactOnGroup.values()) {
       
   462 		    contactByGroups.remove(contact);
       
   463 		}
       
   464 		cleanBannerGroup();
       
   465 	    }
       
   466 	    mListContact = mContactOnGroup.get(getString(R.string.contact_list_all_contact));
       
   467 	    mHandler.post(new RunnableChange());
       
   468 	}
       
   469 
       
   470 	/**
       
   471 	 * {@inheritDoc}
       
   472 	 */
       
   473 	@Override
       
   474 	public void onEntriesUpdated(List<String> addresses) throws RemoteException {
       
   475 	    boolean hideDisconnected = mSettings.getBoolean(SETTINGS_HIDDEN_CONTACT, false);
       
   476 	    for (String adr : addresses) {
       
   477 		Contact c = mRoster.getContact(adr);
       
   478 		List<String> groups = c.getGroups();
       
   479 		for (Map.Entry<String, List<Contact>> entry : mContactOnGroup.entrySet()) {
       
   480 		    List<Contact> contactByGroups = entry.getValue();
       
   481 		    contactByGroups.remove(c);
       
   482 		}
       
   483 		if (!hideDisconnected || Status.statusOnline(c.getStatus())) {
       
   484 		    mContactOnGroup.get(getString(R.string.contact_list_all_contact)).add(c);
       
   485 		    if (c.getGroups().size() == 0)
       
   486 			mContactOnGroup.get(getString(R.string.contact_list_no_group)).add(c);
       
   487 		    for (String group : c.getGroups()) {
       
   488 			if (!mListGroup.contains(group)) {
       
   489 			    mListGroup.add(mListGroup.size() - 1, group);
       
   490 			    List<Contact> tmplist = new LinkedList<Contact>();
       
   491 			    mContactOnGroup.put(group, tmplist);
       
   492 			}
       
   493 			mContactOnGroup.get(group).add(c);
       
   494 		    }
       
   495 		}
       
   496 	    }
       
   497 	    cleanBannerGroup();
       
   498 	    mHandler.post(new RunnableChange());
       
   499 	}
       
   500 
       
   501 	@Override
       
   502 	public void onPresenceChanged(PresenceAdapter presence) throws RemoteException {
       
   503 	    String from = presence.getFrom();
       
   504 	    boolean hideDisconnected = mSettings.getBoolean(SETTINGS_HIDDEN_CONTACT, false);
       
   505 	    Contact contact = mRoster.getContact(StringUtils.parseBareAddress(from));
       
   506 	    for (Map.Entry<String, List<Contact>> entry : mContactOnGroup.entrySet()) {
       
   507 		List<Contact> contactByGroups = entry.getValue();
       
   508 		if (contactByGroups.contains(contact)) {
       
   509 		    contactByGroups.remove(contact);
       
   510 		    if (!hideDisconnected || Status.statusOnline(contact.getStatus())) {
       
   511 			contactByGroups.add(contact);
       
   512 		    }
       
   513 		} else {
       
   514 		    if (Status.statusOnline(contact.getStatus())) {
       
   515 			List<String> groups = contact.getGroups();
       
   516 			if (groups.contains(entry.getKey())) {
       
   517 			    contactByGroups.add(contact);
       
   518 			}
       
   519 		    }
       
   520 		}
       
   521 	    }
       
   522 	    Log.d(TAG, "presence");
       
   523 	    mHandler.post(new RunnableChange());
       
   524 	}
       
   525 
       
   526 	private void cleanBannerGroup() {
       
   527 	    for (Iterator<String> it = mListGroup.iterator(); it.hasNext(); ){
       
   528 		String group = it.next();
       
   529 		if (mContactOnGroup.get(group).size() == 0) {
       
   530 		    mContactOnGroup.remove(group);
       
   531 		    it.remove();
       
   532 		}
       
   533 	    }
       
   534 	}
       
   535 
       
   536     }
       
   537 
       
   538     /**
       
   539      * Adapter contact list.
       
   540      */
       
   541     private class BeemContactList extends BaseAdapter {
       
   542 
       
   543 	/**
       
   544 	 * Constructor.
       
   545 	 */
       
   546 	public BeemContactList() {
       
   547 	}
       
   548 
       
   549 	/**
       
   550 	 * {@inheritDoc}
       
   551 	 */
       
   552 	@Override
       
   553 	public int getCount() {
       
   554 	    return mListContact.size();
       
   555 	}
       
   556 
       
   557 	/**
       
   558 	 * {@inheritDoc}
       
   559 	 */
       
   560 	@Override
       
   561 	public Object getItem(int position) {
       
   562 	    return mListContact.get(position);
       
   563 	}
       
   564 
       
   565 	/**
       
   566 	 * {@inheritDoc}
       
   567 	 */
       
   568 	@Override
       
   569 	public long getItemId(int position) {
       
   570 	    return position;
       
   571 	}
       
   572 
       
   573 	/**
       
   574 	 * {@inheritDoc}
       
   575 	 */
       
   576 	@Override
       
   577 	public View getView(int position, View convertView, ViewGroup parent) {
       
   578 	    View v = convertView;
       
   579 	    if (convertView == null) {
       
   580 		v = mInflater.inflate(R.layout.contactlistcontact, null);
       
   581 	    }
       
   582 	    Contact c = mListContact.get(position);
       
   583 	    if (mRoster != null) {
       
   584 		try {
       
   585 		    c = mRoster.getContact(c.getJID());
       
   586 		} catch (RemoteException e) {
       
   587 		    e.printStackTrace();
       
   588 		}
       
   589 	    }
       
   590 	    bindView(v, c);
       
   591 	    return v;
       
   592 	}
       
   593 
       
   594 	/**
       
   595 	 * Adapte curContact to the view.
       
   596 	 * @param view the row view.
       
   597 	 * @param curContact the current contact.
       
   598 	 */
       
   599 	private void bindView(View view, Contact curContact) {
       
   600 
       
   601 	    if (curContact != null) {
       
   602 		TextView v = (TextView) view.findViewById(R.id.contactlistpseudo);
       
   603 		LevelListDrawable mStatusDrawable = (LevelListDrawable) getResources().getDrawable(R.drawable.status_icon);
       
   604 		mStatusDrawable.setLevel(curContact.getStatus());
       
   605 		v.setCompoundDrawablesWithIntrinsicBounds(mStatusDrawable, null, null, null);
       
   606 		v.setText(curContact.getName());
       
   607 		v = (TextView) view.findViewById(R.id.contactlistmsgperso);
       
   608 		v.setText(curContact.getMsgState());
       
   609 	    }
       
   610 	}
       
   611     }
       
   612 
       
   613     /**
       
   614      * Adapter banner list.
       
   615      */
       
   616     private static class BeemBanner extends BaseAdapter {
       
   617 	private List<String> mGroups;
       
   618 	private LayoutInflater mInflater;
       
   619 
       
   620 	/**
       
   621 	 * Constructor.
       
   622 	 */
       
   623 	public BeemBanner(LayoutInflater inflater, List<String> groups) {
       
   624 	    mGroups = groups;
       
   625 	    mInflater = inflater;
       
   626 	}
       
   627 
       
   628 	@Override
       
   629 	public int getCount() {
       
   630 	    return mGroups.size();
       
   631 	}
       
   632 
       
   633 	@Override
       
   634 	public Object getItem(int position) {
       
   635 	    return mGroups.get(position);
       
   636 	}
       
   637 
       
   638 	@Override
       
   639 	public long getItemId(int position) {
       
   640 	    return position;
       
   641 	}
       
   642 
       
   643 	@Override
       
   644 	public View getView(int position, View convertView, ViewGroup parent) {
       
   645 	    View v = convertView;
       
   646 	    if (convertView == null) {
       
   647 		v = mInflater.inflate(R.layout.contactlist_group, null);
       
   648 	    }
       
   649 	    ((TextView) v).setText(mGroups.get(position));
       
   650 	    return v;
       
   651 	}
       
   652     }
       
   653 
       
   654     /**
       
   655      * The service connection used to connect to the Beem service.
       
   656      */
       
   657     private class BeemServiceConnection implements ServiceConnection {
       
   658 
       
   659 	/**
       
   660 	 * Constructor.
       
   661 	 */
       
   662 	public BeemServiceConnection() {
       
   663 	}
       
   664 
       
   665 	@Override
       
   666 	public void onServiceConnected(ComponentName name, IBinder service) {
       
   667 	    mXmppFacade = IXmppFacade.Stub.asInterface(service);
       
   668 	    try {
       
   669 		mRoster = mXmppFacade.getRoster();
       
   670 		if (mRoster != null) {
       
   671 		    mRoster.addRosterListener(mBeemRosterListener);
       
   672 		    List<Contact> tmpContactList = mRoster.getContactList();
       
   673 		    List<String> tmpGroupList = mRoster.getGroupsNames();
       
   674 		    Collections.sort(tmpGroupList);
       
   675 		    if (mListGroup.size() > 0)
       
   676 			mListGroup.clear();
       
   677 		    mListGroup.add(getString(R.string.contact_list_all_contact));
       
   678 		    mListGroup.addAll(tmpGroupList);
       
   679 		    mListGroup.add(getString(R.string.contact_list_no_group));
       
   680 		    assignContactToGroups(mRoster.getContactList(), tmpGroupList);
       
   681 		    if (!mSettings.getBoolean("settings_key_hide_groups", false))
       
   682 			showGroups();
       
   683 		    else
       
   684 			hideGroups();
       
   685 		    String group = getString(R.string.contact_list_all_contact);
       
   686 		    buildContactList(group);
       
   687 		}
       
   688 	    } catch (RemoteException e) {
       
   689 		e.printStackTrace();
       
   690 	    }
       
   691 	}
       
   692 
       
   693 	@Override
       
   694 	public void onServiceDisconnected(ComponentName name) {
       
   695 	    try {
       
   696 		mRoster.removeRosterListener(mBeemRosterListener);
       
   697 	    } catch (RemoteException e) {
       
   698 		e.printStackTrace();
       
   699 	    }
       
   700 	    mXmppFacade = null;
       
   701 	    mRoster = null;
       
   702 	    mListContact.clear();
       
   703 	    mListGroup.clear();
       
   704 	    mContactOnGroup.clear();
       
   705 	    mBinded = false;
       
   706 	}
       
   707     }
       
   708 
       
   709     @Override
       
   710     protected void finalize() {
       
   711 	Log.e(TAG, "FINALIZE");
       
   712     }
       
   713 
       
   714     /**
       
   715      * Hide the groups view.
       
   716      */
       
   717     private void hideGroups() {
       
   718 	View v = findViewById(R.id.contactlist_groupstub);
       
   719 	if (v != null)
       
   720 	    v.setVisibility(View.GONE);
       
   721     }
       
   722 
       
   723     private void assignContactToGroups(List<Contact> contacts, List<String> groupNames) {
       
   724 	boolean hideDisconnected = mSettings.getBoolean(SETTINGS_HIDDEN_CONTACT, false);
       
   725 	mContactOnGroup.clear();
       
   726 	List<Contact> all = new LinkedList<Contact>();
       
   727 	List<Contact> noGroups = new LinkedList<Contact>();
       
   728 	for (String group: groupNames) {
       
   729 	    mContactOnGroup.put(group, new LinkedList<Contact>());
       
   730 	}
       
   731 	for (Contact c : contacts) {
       
   732 	    if (hideDisconnected && !Status.statusOnline(c.getStatus())) {
       
   733 		continue;
       
   734 	    }
       
   735 	    all.add(c);
       
   736 	    List<String> groups = c.getGroups();
       
   737 	    if (groups.size() == 0)
       
   738 		noGroups.add(c);
       
   739 	    else {
       
   740 		for (String currentGroup : groups) {
       
   741 		    List<Contact> contactsByGroups = mContactOnGroup.get(currentGroup);
       
   742 		    contactsByGroups.add(c);
       
   743 		}
       
   744 	    }
       
   745 	}
       
   746 	mContactOnGroup.put(getString(R.string.contact_list_no_group), noGroups);
       
   747 	mContactOnGroup.put(getString(R.string.contact_list_all_contact), all);
       
   748     }
       
   749 }
   847 }