Can now configure adapter based on viewtype. Added section divider.

Change-Id: I7708fcfd1910082bb38f2044377b75161248e6a1
diff --git a/res/layout/contact_tile_regular.xml b/res/layout/contact_tile_regular.xml
index 571a9be..3fbc0fb 100644
--- a/res/layout/contact_tile_regular.xml
+++ b/res/layout/contact_tile_regular.xml
@@ -18,10 +18,12 @@
     class="com.android.contacts.list.ContactTileView"
     style="@style/ContactTileRegularLayout">
 
-        <ImageView android:id="@+id/contact_tile_image"
-            style="@style/ContactTileRegularImage" />
+    <ImageView
+        android:id="@+id/contact_tile_image"
+        style="@style/ContactTileRegularImage" />
 
-        <TextView android:id="@+id/contact_tile_name"
-            style="@style/ContactTileRegularText" />
+    <TextView
+        android:id="@+id/contact_tile_name"
+        style="@style/ContactTileRegularText" />
 
 </view>
diff --git a/res/layout/contact_tile_small.xml b/res/layout/contact_tile_small.xml
new file mode 100644
index 0000000..a750943
--- /dev/null
+++ b/res/layout/contact_tile_small.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<view
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    class="com.android.contacts.list.ContactTileView"
+    style="@style/ContactTileSmallLayout">
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content">
+        <ImageView
+            android:id="@+id/contact_tile_image"
+            style="@style/ContactTileSmallImage" />
+        <TextView
+            android:id="@+id/contact_tile_name"
+            style="@style/ContactTileSmallText" />
+    </LinearLayout>
+
+</view>
diff --git a/res/layout/list_separator.xml b/res/layout/list_separator.xml
index 9f562cf..af83584 100644
--- a/res/layout/list_separator.xml
+++ b/res/layout/list_separator.xml
@@ -18,4 +18,5 @@
 <TextView xmlns:android="http://schemas.android.com/apk/res/android"
     style="?android:attr/listSeparatorTextViewStyle"
     android:gravity="left|center_vertical"
+    android:id="@+id/header_text"
 />
diff --git a/src/com/android/contacts/list/ContactTileAdapter.java b/src/com/android/contacts/list/ContactTileAdapter.java
index dbfa030..32a68cb 100644
--- a/src/com/android/contacts/list/ContactTileAdapter.java
+++ b/src/com/android/contacts/list/ContactTileAdapter.java
@@ -29,137 +29,306 @@
 import android.view.ViewGroup;
 import android.widget.BaseAdapter;
 import android.widget.LinearLayout;
+import android.widget.TextView;
 
 import java.util.ArrayList;
 
 /**
- * Arranges contacts in {@link StrequentFragment} (aka favorites) according to if the contact
- * is starred or not. Also shows a configurable but fixed number of contacts per row.
+ * Arranges contacts in {@link StrequentContactListFragment} (aka favorites) according to
+ * provided {@link DisplayType}.
+ * Also allows for a configurable number of columns and {@link DisplayType}
  */
 public class ContactTileAdapter extends BaseAdapter {
     private static final String TAG = "ContactTileAdapter";
 
-    private ArrayList<StrequentEntry> mAllEntries;
+    /**
+     * mContacts2 is only used if {@link DisplayType} is Strequent
+     * All starred contacts are placed into mContacts2
+     */
+    private ArrayList<ContactEntry> mContacts2 = new ArrayList<ContactEntry>();
+
+    /**
+     * In {@link DisplayType#STREQUENT} only the frequently contacted
+     * contacts will be placed into mContacts.
+     * All other {@link DisplayType} will put all contacts into mContacts.
+     */
+    private ArrayList<ContactEntry> mContacts = new ArrayList<ContactEntry>();
+    private DisplayType mDisplayType;
     private Listener mListener;
-    private int mMostFrequentCount;
-    private int mStarredCount;
     private Context mContext;
     private int mColumnCount;
+    private int mDividerRowIndex;
     private ContactPhotoManager mPhotoManager;
 
-    public ContactTileAdapter(Context context, Listener listener, int numCols) {
+    /**
+     * Configures the adapter to filter and display contacts using different view types.
+     * TODO: Create Uris to support getting Starred_only and Frequent_only cursors.
+     */
+    public enum DisplayType {
+        /**
+         * Displays a mixed view type where Starred Contacts
+         * are in a regular {@link ContactTileView} layout and
+         * frequent contacts are in a small {@link ContactTileView} layout.
+         */
+        STREQUENT,
+
+        /**
+         * Display only starred contacts in
+         * regular {@link ContactTileView} layout.
+         */
+        STARRED_ONLY,
+
+        /**
+         * Display only most frequently contacted in a
+         * small {@link ContactTileView} layout.
+         */
+        FREQUENT_ONLY,
+
+        /**
+         * Display all contacts from a group in the cursor in a
+         * regular {@link ContactTileView} layout.
+         */
+        GROUP_MEMBERS
+    }
+
+    public ContactTileAdapter(Context context, Listener listener, int numCols,
+            DisplayType displayType) {
         mListener = listener;
         mContext = context;
         mColumnCount = numCols;
-        mPhotoManager = ContactPhotoManager.createContactPhotoManager(context);
+        mPhotoManager = ContactPhotoManager.getInstance(context);
+        mDisplayType = displayType;
     }
 
-    public void setCursor(Cursor cursor){
-        populateStrequentEntries(cursor);
-    }
-
-    private void populateStrequentEntries(Cursor cursor) {
-        mAllEntries = new ArrayList<StrequentEntry>();
-        mMostFrequentCount = mStarredCount = 0;
+    public void loadFromCursor(Cursor cursor) {
+        mContacts.clear();
+        mContacts2.clear();
 
         // If the loader was canceled we will be given a null cursor.
         // In that case, show an empty list of contacts.
         if (cursor != null) {
             while (cursor.moveToNext()) {
-                StrequentEntry contact = new StrequentEntry();
+                ContactEntry contact = new ContactEntry();
 
                 long id = cursor.getLong(StrequentMetaDataLoader.CONTACT_ID);
                 String lookupKey = cursor.getString(StrequentMetaDataLoader.LOOKUP_KEY);
                 String photoUri = cursor.getString(StrequentMetaDataLoader.PHOTO_URI);
 
-                if (photoUri != null) contact.photoUri = Uri.parse(photoUri);
-                else contact.photoUri = null;
+                contact.photoUri = (photoUri != null ? Uri.parse(photoUri) : null);
 
                 contact.lookupKey = ContentUris.withAppendedId(
                         Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey), id);
                 contact.name = cursor.getString(StrequentMetaDataLoader.DISPLAY_NAME);
 
-                if (cursor.getInt(StrequentMetaDataLoader.STARRED) == 1) mStarredCount++;
-                else mMostFrequentCount++;
+                boolean isStarred = (cursor.getInt(StrequentMetaDataLoader.STARRED) == 1);
 
-                mAllEntries.add(contact);
+                switch (mDisplayType) {
+                    case STREQUENT:
+                        (isStarred ? mContacts2 : mContacts).add(contact);
+                        break;
+                    case STARRED_ONLY:
+                        if (isStarred) {
+                            mContacts.add(contact);
+                        }
+                        break;
+                    case FREQUENT_ONLY:
+                        if (!isStarred) {
+                            mContacts.add(contact);
+                        }
+                        break;
+                    case GROUP_MEMBERS:
+                        mContacts.add(contact);
+                        break;
+                    default:
+                        throw new IllegalArgumentException("Unrecognized displayType");
+                }
             }
         }
+
+        mDividerRowIndex =
+                (mDisplayType == DisplayType.STREQUENT ? getNumRows(mContacts2.size()) : -1);
         notifyDataSetChanged();
     }
 
     @Override
-    /*
-     * Doing some math to make sure number to rounded up to account
-     * for a partially filled row, if necessary.
-     */
     public int getCount() {
-        return ((mAllEntries.size() - 1) / mColumnCount) + 1;
+        int numRows = getNumRows(mContacts2.size()) + getNumRows(mContacts.size());
+        // Adding Divider Row if Neccessary
+        if (mDisplayType == DisplayType.STREQUENT && mContacts.size() > 0) numRows++;
+        return numRows;
     }
 
+    /**
+     * Returns the number of rows required to show the provided number of entries
+     * with the current number of columns.
+     */
+    private int getNumRows(int entryCount) {
+        return entryCount == 0 ? 0 : ((entryCount - 1) / mColumnCount) + 1;
+    }
+
+    /**
+     * Returns an ArrayList of the {@link ContactEntry}s that are to appear
+     * on the row for the given position.
+     */
     @Override
-    public Object getItem(int position) {
-        return mAllEntries.get(position);
+    public ArrayList<ContactEntry> getItem(int position) {
+        if (position == mDividerRowIndex) return null;
+        ArrayList<ContactEntry> resultList = new ArrayList<ContactEntry>();
+
+        // Determining which Arraylist to use for display
+        int contactIndex = position * mColumnCount;
+        ArrayList<ContactEntry> contactList;
+        if (contactIndex < mContacts2.size()) {
+            contactList = mContacts2;
+        } else {
+            if (mDisplayType == DisplayType.STREQUENT) {
+                contactIndex = (position - mDividerRowIndex - 1) * mColumnCount;
+            }
+            contactList = mContacts;
+        }
+
+        // Populating with the Contacts to appear at position
+        for (int columnCounter = 0; columnCounter < mColumnCount; columnCounter++) {
+            if (contactIndex >= contactList.size()) break;
+            resultList.add(contactList.get(contactIndex));
+            contactIndex++;
+        }
+
+        return resultList;
     }
 
     @Override
     public long getItemId(int position) {
-        return 1;
+        /*
+         * As we show several selectable items for each ListView row,
+         * we can not determine a stable id. But as we don't rely on ListView's selection,
+         * this should not be a problem.
+         */
+        return position;
+    }
+
+    @Override
+    public boolean areAllItemsEnabled() {
+        return mDisplayType != DisplayType.STREQUENT;
+    }
+
+    @Override
+    public boolean isEnabled(int position) {
+        return position != mDividerRowIndex;
     }
 
     @Override
     public View getView(int position, View convertView, ViewGroup parent) {
-        int rowIndex = position * mColumnCount;
+
+        // Checking position to draw the divider
+        if (position == mDividerRowIndex) {
+            return convertView == null ? createDivider() : convertView;
+        }
+
         ContactTileRow contactTileRowView = (ContactTileRow) convertView;
+        ArrayList<ContactEntry> contactList = getItem(position);
 
+        // Creating new row if needed
         if (contactTileRowView == null) {
-            contactTileRowView = new ContactTileRow(mContext);
+            int layoutResId = getLayoutResourceId(getItemViewType(position));
+            contactTileRowView = new ContactTileRow(mContext, layoutResId);
         }
 
-        for (int columnCounter = 0; columnCounter < mColumnCount; columnCounter++) {
-            int contactIndex = rowIndex + columnCounter;
+        contactTileRowView.configureRow(contactList);
 
-            if (contactIndex >= mAllEntries.size()) {
-                contactTileRowView.removeViewAt(columnCounter);
-            } else {
-                contactTileRowView.addTileFromEntry(mAllEntries.get(contactIndex), columnCounter);
-            }
-        }
         return contactTileRowView;
     }
 
-    @Override
-    public int getViewTypeCount() {
-        return 1;
+    /**
+     * Divider uses a list_seperator.xml along with text to denote
+     * the most frequently contacted contacts.
+     */
+    private View createDivider() {
+        View dividerView = View.inflate(mContext, R.layout.list_separator, null);
+        dividerView.setFocusable(false);
+        TextView text = (TextView) dividerView.findViewById(R.id.header_text);
+        text.setText(mContext.getString(R.string.favoritesFrquentSeparator));
+        return dividerView;
     }
 
+    private int getLayoutResourceId(int viewType) {
+        switch (viewType) {
+            case ViewTypes.SMALL:
+                return R.layout.contact_tile_small;
+            case ViewTypes.REGULAR:
+                return R.layout.contact_tile_regular;
+            default:
+                throw new IllegalArgumentException("Received unrecognized viewType " + viewType);
+        }
+    }
+    @Override
+    public int getViewTypeCount() {
+        return mDisplayType == DisplayType.STREQUENT ? ViewTypes.COUNT : 1;
+    }
+
+    /**
+     * Returns view type based on {@link DisplayType}.
+     * STARRED_ONLY and GROUP_MEMBERS are {@link ViewTypes}.REGULAR.
+     * FREQUENT_ONLY is {@link ViewTypes}.SMALL.
+     * STREQUENT mixes both {@link ViewTypes} and also adds in {@link ViewTypes}.DIVIDER.
+     */
     @Override
     public int getItemViewType(int position) {
-        return 1;
+        switch (mDisplayType) {
+            case STREQUENT:
+                if (position < mDividerRowIndex) {
+                    return ViewTypes.REGULAR;
+                } else if (position == mDividerRowIndex) {
+                    return ViewTypes.DIVIDER;
+                } else {
+                    return ViewTypes.SMALL;
+                }
+            case STARRED_ONLY:
+            case GROUP_MEMBERS:
+                return ViewTypes.REGULAR;
+            case FREQUENT_ONLY:
+                return ViewTypes.SMALL;
+            default:
+                throw new IllegalStateException(
+                        "Received unrecognized DisplayType " + mDisplayType);
+        }
     }
 
     /**
      * Acts as a row item composed of {@link ContactTileView}
      */
     private class ContactTileRow extends LinearLayout implements OnClickListener {
+        private int mLayoutResId;
 
-        public ContactTileRow(Context context) {
+        public ContactTileRow(Context context, int layoutResId) {
             super(context);
+            mLayoutResId = layoutResId;
         }
 
-        public void addTileFromEntry(StrequentEntry entry, int tileIndex) {
+        /**
+         * Configures the row to add {@link ContactEntry}s information to the views
+         */
+        public void configureRow(ArrayList<ContactEntry> list) {
+            // Adding tiles to row and filling in contact information
+            for (int columnCounter = 0; columnCounter < mColumnCount; columnCounter++) {
+                ContactEntry entry =
+                        columnCounter < list.size() ? list.get(columnCounter) : null;
+                addTileFromEntry(entry, columnCounter);
+            }
+        }
+
+        private void addTileFromEntry(ContactEntry entry, int tileIndex) {
             ContactTileView contactTile;
 
             if (getChildCount() <= tileIndex) {
-                contactTile = (ContactTileView)
-                        inflate(mContext, R.layout.contact_tile_regular, null);
-
-                contactTile.setContactPhotoManager(mPhotoManager);
+                contactTile = (ContactTileView) inflate(mContext, mLayoutResId, null);
+                contactTile.setPhotoManager(mPhotoManager);
                 contactTile.setOnClickListener(this);
                 addView(contactTile);
             } else {
                 contactTile = (ContactTileView) getChildAt(tileIndex);
             }
+            contactTile.setClickable(entry != null);
             contactTile.loadFromContact(entry);
         }
 
@@ -172,12 +341,19 @@
     /**
      * Class to hold contact information
      */
-    public static class StrequentEntry {
+    public static class ContactEntry {
         public Uri photoUri;
         public String name;
         public Uri lookupKey;
     }
 
+    private static class ViewTypes {
+        public static final int COUNT = 3;
+        public static final int SMALL = 0;
+        public static final int REGULAR = 1;
+        public static final int DIVIDER = 2;
+    }
+
     public interface Listener {
         public void onContactSelected(Uri contactUri);
     }
diff --git a/src/com/android/contacts/list/ContactTileView.java b/src/com/android/contacts/list/ContactTileView.java
index 06dbc1d..d19ca7e 100644
--- a/src/com/android/contacts/list/ContactTileView.java
+++ b/src/com/android/contacts/list/ContactTileView.java
@@ -17,12 +17,13 @@
 
 import com.android.contacts.ContactPhotoManager;
 import com.android.contacts.R;
-import com.android.contacts.list.ContactTileAdapter.StrequentEntry;
+import com.android.contacts.list.ContactTileAdapter.ContactEntry;
 
 import android.content.Context;
 import android.net.Uri;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.view.View;
 import android.widget.ImageView;
 import android.widget.RelativeLayout;
 import android.widget.TextView;
@@ -36,11 +37,10 @@
     private Uri mLookupUri;
     private ImageView mPhoto;
     private TextView mName;
-    private ContactPhotoManager mPhotoManager;
+    private ContactPhotoManager mPhotoManager = null;
 
     public ContactTileView(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mPhotoManager = ContactPhotoManager.createContactPhotoManager(context);
     }
 
     @Override
@@ -50,24 +50,27 @@
         mPhoto = (ImageView) findViewById(R.id.contact_tile_image);
     }
 
-    public void loadFromContact(StrequentEntry entry) {
+    public void setPhotoManager(ContactPhotoManager photoManager) {
+        mPhotoManager = photoManager;
+    }
+
+    public void loadFromContact(ContactEntry entry) {
         if (entry != null) {
             mName.setText(entry.name);
             mLookupUri = entry.lookupKey;
+            mPhoto.setImageBitmap(null);
+            setVisibility(View.VISIBLE);
 
-            if (mPhotoManager != null) mPhotoManager.loadPhoto(mPhoto, entry.photoUri);
-            else Log.w(TAG, "contactPhotoManger not set");
-
+            if (mPhotoManager != null) {
+                mPhotoManager.loadPhoto(mPhoto, entry.photoUri);
+            } else {
+                Log.w(TAG, "contactPhotoManager not set");
+            }
         } else {
-            Log.w(TAG, "loadFromContact received null formal");
-            throw new IllegalArgumentException();
+            setVisibility(View.INVISIBLE);
         }
     }
 
-    public void setContactPhotoManager(ContactPhotoManager manager) {
-        mPhotoManager = manager;
-    }
-
     public Uri getLookupUri() {
         return mLookupUri;
     }
diff --git a/src/com/android/contacts/list/StrequentContactListFragment.java b/src/com/android/contacts/list/StrequentContactListFragment.java
index 82d596f..d2e2ca3 100644
--- a/src/com/android/contacts/list/StrequentContactListFragment.java
+++ b/src/com/android/contacts/list/StrequentContactListFragment.java
@@ -17,6 +17,7 @@
 
 import com.android.contacts.R;
 import com.android.contacts.StrequentMetaDataLoader;
+import com.android.contacts.list.ContactTileAdapter.DisplayType;
 
 import android.app.Activity;
 import android.app.Fragment;
@@ -53,7 +54,8 @@
     @Override
     public void onAttach(Activity activity) {
         super.onAttach(activity);
-        mAdapter = new ContactTileAdapter(activity, mAdapterListener, NUM_COLS);
+        mAdapter = new ContactTileAdapter(activity, mAdapterListener,
+                NUM_COLS, DisplayType.STREQUENT);
         mContext = activity;
     }
 
@@ -73,9 +75,7 @@
     @Override
     public void onStart(){
         super.onStart();
-        // Commenting this out temporarily to fix a crash on load
-        // TODO: Bring this back
-//        getLoaderManager().restartLoader(LOADER_STREQUENT, null, mStrequentLoaderListener);
+        getLoaderManager().restartLoader(LOADER_STREQUENT, null, mStrequentLoaderListener);
     }
 
     /**
@@ -91,13 +91,13 @@
 
         @Override
         public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
-            mAdapter.setCursor(data);
+            mAdapter.loadFromCursor(data);
             mListView.setAdapter(mAdapter);
         }
 
         @Override
         public void onLoaderReset(Loader<Cursor> loader) {
-            mAdapter.setCursor(null);
+            mAdapter.loadFromCursor(null);
         }
     };