* #31001: com.savoirfaire -> org.sflphone
diff --git a/src/org/sflphone/adapters/ContactsAdapter.java b/src/org/sflphone/adapters/ContactsAdapter.java
new file mode 100644
index 0000000..3342c5a
--- /dev/null
+++ b/src/org/sflphone/adapters/ContactsAdapter.java
@@ -0,0 +1,322 @@
+package org.sflphone.adapters;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import org.sflphone.model.CallContact;
+
+import android.content.Context;
+import android.util.SparseArray;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.SectionIndexer;
+import android.widget.TextView;
+
+import org.sflphone.R;
+
+public class ContactsAdapter extends BaseAdapter implements SectionIndexer {
+
+    private ExecutorService infos_fetcher = Executors.newCachedThreadPool();
+    Context mContext;
+
+    HashMap<String, Integer> alphaIndexer;
+    String[] sections;
+
+//    private static final String TAG = ContactsAdapter.class.getSimpleName();
+
+    public ContactsAdapter(Context context) {
+        super();
+        mContext = context;
+        alphaIndexer = new HashMap<String, Integer>();
+        headers = new HeadersHolder(new ArrayList<CallContact>());
+    }
+
+    HeadersHolder headers;
+    private static final int TYPE_HEADER = 0;
+    private static final int TYPE_TRACK = 1;
+
+    @Override
+    public View getView(int position, View convertView, ViewGroup parent) {
+        int type = getItemViewType(position);
+
+//        Log.i(TAG, "positon" + position + " type " + type);
+        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+        switch (type) {
+        case TYPE_TRACK:
+            return getViewTrack(position, inflater, convertView);
+        case TYPE_HEADER:
+            return getViewHeader(position, inflater, convertView);
+        }
+        return null;
+    }
+
+    private View getViewHeader(int position, LayoutInflater inflater, View convertView) {
+        if (convertView == null) {
+            convertView = inflater.inflate(R.layout.header, null);
+        }
+        TextView name = (TextView) convertView.findViewById(R.id.header_letter);
+        name.setText(headers.getSection(position));
+        return convertView;
+    }
+
+    private View getViewTrack(int position, LayoutInflater inflater, View convertView) {
+
+        if (convertView == null) {
+            convertView = inflater.inflate(R.layout.item_contact, null);
+        }
+
+        CallContact item = headers.getCallContact(position);
+
+        ((TextView) convertView.findViewById(R.id.display_name)).setText(item.getmDisplayName());
+        ImageView photo_view = (ImageView) convertView.findViewById(R.id.photo);
+
+        infos_fetcher.execute(new ContactPictureTask(mContext, photo_view, item.getId()));
+
+        return convertView;
+    }
+
+    @Override
+    public int getCount() {
+        return headers.size() + headers.getSections().size();
+    }
+
+    @Override
+    public int getItemViewType(int pos) {
+        return (headers.contains(pos) ? TYPE_HEADER : TYPE_TRACK);
+    }
+
+    @Override
+    public int getViewTypeCount() {
+        return 2;
+    }
+
+
+
+    @Override
+    public long getItemId(int position) {
+        return 0;
+    }
+
+    public void removeAll() {
+        headers.clear();
+        notifyDataSetChanged();
+    }
+
+    public void add(CallContact tr) {
+        headers.add(tr);
+        headers.buildIndex();
+    }
+
+    public void addAll(ArrayList<CallContact> tr) {
+        headers = new HeadersHolder(tr);
+        notifyDataSetChanged();
+    }
+
+
+    @Override
+    public int getPositionForSection(int section) {
+        return headers.getPositionFor(section);
+    }
+
+    @Override
+    public int getSectionForPosition(int position) {
+        return headers.getSectionFor(position);
+    }
+
+    @Override
+    public Object[] getSections() {
+        return headers.getSectionsArray();
+    }
+
+    public int getRealPosition(int pos) {
+        return headers.getTrackPosition(pos);
+    }
+
+    @Override
+    public CallContact getItem(int index) {
+        return headers.getCallContact(index);
+    }
+   
+    public class HeadersHolder {
+
+        public static final String TAG = "HeadersHolder";
+        HashMap<String, Integer> alphaIndexer;
+        ArrayList<CallContact> contacts;
+
+        String[] sectionsArray;
+
+        public String[] getSectionsArray() {
+            return sectionsArray;
+        }
+
+        int headersCount;
+        private SparseArray<Item> items = new SparseArray<Item>();
+
+        public SparseArray<Item> getItems() {
+            return items;
+        }
+
+        public void setItems(SparseArray<Item> items) {
+            this.items = items;
+        }
+
+        public SparseArray<Section> getSections() {
+            return sections;
+        }
+
+        public void setSections(SparseArray<Section> sections) {
+            this.sections = sections;
+        }
+
+        private SparseArray<Section> sections = new SparseArray<Section>();
+
+        public HeadersHolder(ArrayList<CallContact> a) {
+            alphaIndexer = new HashMap<String, Integer>();
+            contacts = a;
+            headersCount = 0;
+            buildIndex();
+        }
+
+        // public int getHeadersCount() {
+        // return headersCount;
+        // }
+
+        private class Item {
+            public Item(int rpos, int headersCount2, CallContact track) {
+//                Log.i(TAG, "Creating Item");
+
+                sectionNumber = headersCount2;
+                realPos = rpos;
+                tr = track;
+
+            }
+
+            public int realPos;
+            public int sectionNumber;
+            public CallContact tr;
+        }
+
+        private class Section {
+//            public int startPosition;
+            public int number;
+            public String header;
+
+            public Section(int i, int headersCount, String str) {
+//                Log.i(TAG, "Creating section");
+
+//                startPosition = i + headersCount;
+                number = headersCount;
+                header = str;
+
+            }
+
+            @Override
+            public String toString() {
+                return header;
+            }
+        }
+
+        public void buildIndex() {
+
+            for (int x = 0; x < contacts.size(); x++) {
+                String s = contacts.get(x).getmDisplayName();
+                String ch = s.substring(0, 1);
+                ch = ch.toUpperCase(Locale.CANADA);
+                if (!alphaIndexer.containsKey(ch)) {
+                    sections.put(x + headersCount, new Section(x, headersCount, ch));
+                    headersCount++;
+                }
+                Integer result = alphaIndexer.put(ch, x + headersCount);
+                items.put(x + headersCount, new Item(x, headersCount, contacts.get(x)));
+                if (result == null) {
+
+                }
+            }
+
+            Set<String> sect = alphaIndexer.keySet();
+
+            // create a list from the set to sort
+            ArrayList<String> sectionList = new ArrayList<String>(sect);
+            Collections.sort(sectionList);
+            sectionsArray = new String[sectionList.size()];
+            sectionList.toArray(sectionsArray);
+
+        }
+
+        public HashMap<String, Integer> getAlphaIndexer() {
+            return alphaIndexer;
+        }
+
+        public int getPositionFor(int section) {
+            if (section == sectionsArray.length)
+                return sectionsArray.length;
+            return alphaIndexer.get(sectionsArray[section]);
+        }
+
+        public int getSectionFor(int position) {
+            return (null != items.get(position)) ? items.get(position).sectionNumber : sections.get(position).number;
+        }
+
+        public boolean contains(int pos) {
+            if (sections.get(pos) != null) {
+                return true;
+            }
+            return false;
+        }
+
+        public CallContact getCallContact(int position) {
+
+            if (items.get(position) == null)
+                return null;
+
+            return items.get(position).tr;
+
+        }
+
+        public int size() {
+            return contacts.size();
+        }
+
+        public void clear() {
+            contacts.clear();
+
+        }
+
+        public void add(CallContact tr) {
+            contacts.add(tr);
+
+        }
+
+        public void addAll(ArrayList<CallContact> tr) {
+            contacts.clear();
+            contacts.addAll(tr);
+
+        }
+
+        public ArrayList<CallContact> getTracks() {
+            return contacts;
+        }
+
+        public int getTrackPosition(int pos) {
+            if (sections.get(pos) != null) {
+                return items.get(pos + 1).realPos;
+            }
+            return items.get(pos).realPos;
+        }
+
+        public CharSequence getSection(int position) {
+            return sections.get(position).header;
+        }
+
+    }
+
+}