Support scrolling of Updates tab.

This commit changes the Updates tab to use a ListView for its items. The
ListView has an extra header item that overlaps with the carousel tab
(if present), and implements the scrolling which hides part of the
carousel (excluding the tab itself).

The fragment now basically contains only a list view, which will store
all the items, and an optional title (I need to check if that's actually
needed, but for now it is there).

The extra header is implemented with a layout: for those configurations
where there is a carousel, the header contains a placeholder which is
the same size as the carousel; for those configurations where there is
no carousel, the header will be an empty FrameLayout (but in those same
cases, there is a header at the top of the list in the fragment's
layout).

This commit does not take care of making the scrolling work across the
two tabs, e.g., when switching between tabs. I will address those issues
in a follow-up.

Bug: 5119353
Change-Id: I0eb6dcc06d624991ab1f5f8fe1197337ba03286b
diff --git a/res/layout-sw580dp-w1000dp/contact_detail_updates_fragment.xml b/res/layout-sw580dp-w1000dp/contact_detail_updates_fragment.xml
index 9b63ccf..427f369 100644
--- a/res/layout-sw580dp-w1000dp/contact_detail_updates_fragment.xml
+++ b/res/layout-sw580dp-w1000dp/contact_detail_updates_fragment.xml
@@ -14,51 +14,22 @@
      limitations under the License.
 -->
 
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:ex="http://schemas.android.com/apk/res/com.android.contacts"
     android:id="@+id/contact_detail_updates_fragment"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:padding="16dip">
 
-    <ScrollView
+    <include
+        android:id="@+id/title"
+        layout="@layout/contact_detail_kind_title_entry_view" />
+
+    <ListView android:id="@android:id/list"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:background="@color/background_social_updates">
+        android:layout_height="wrap_content"
+        android:background="@color/background_social_updates"
+        android:divider="@null"/>
 
-        <LinearLayout
-            android:orientation="vertical"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:paddingTop="@dimen/detail_update_section_top_padding">
-
-            <include
-                android:id="@+id/title"
-                layout="@layout/contact_detail_kind_title_entry_view" />
-
-            <LinearLayout
-                android:id="@+id/update_list"
-                android:orientation="vertical"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:paddingLeft="@dimen/detail_update_section_side_padding"
-                android:paddingRight="@dimen/detail_update_section_side_padding" />
-        </LinearLayout>
-
-    </ScrollView>
-
-    <View
-        android:id="@+id/alpha_overlay"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:background="@android:color/black"
-        android:alpha=".50"
-        android:visibility="gone"/>
-
-    <View
-        android:id="@+id/touch_intercept_overlay"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:background="@android:color/transparent"
-        android:visibility="gone"/>
-
-</FrameLayout>
+</LinearLayout>
diff --git a/res/layout-sw580dp-w1000dp/updates_header_contact.xml b/res/layout-sw580dp-w1000dp/updates_header_contact.xml
new file mode 100644
index 0000000..da63d20
--- /dev/null
+++ b/res/layout-sw580dp-w1000dp/updates_header_contact.xml
@@ -0,0 +1,24 @@
+<?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.
+-->
+
+<!--
+  This is a header entry in the contact updates list.
+  This is empty because there is no header in this case.
+-->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="0dip"/>
diff --git a/res/layout-sw580dp/contact_detail_updates_fragment.xml b/res/layout-sw580dp/contact_detail_updates_fragment.xml
index ce3f661..d73275e 100644
--- a/res/layout-sw580dp/contact_detail_updates_fragment.xml
+++ b/res/layout-sw580dp/contact_detail_updates_fragment.xml
@@ -14,52 +14,18 @@
      limitations under the License.
 -->
 
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:ex="http://schemas.android.com/apk/res/com.android.contacts"
     android:id="@+id/contact_detail_updates_fragment"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
-    <ScrollView
+    <ListView android:id="@android:id/list"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:background="@color/background_social_updates">
-
-        <LinearLayout
-            android:orientation="vertical"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:paddingTop="@dimen/detail_update_section_top_padding">
-
-            <!-- Add a first item that gives us enough space to show the carousel -->
-            <view
-                class="com.android.contacts.widget.ProportionalLayout"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                ex:ratio="0.66"
-                ex:direction="widthToHeight">
-
-                <!-- Put a dummy view here because the ProportionalLayout requires one -->
-                <View
-                    android:layout_width="match_parent"
-                    android:layout_height="match_parent" />
-
-            </view>
-
-            <include
-                android:id="@+id/title"
-                layout="@layout/contact_detail_kind_title_entry_view" />
-
-            <LinearLayout
-                android:id="@+id/update_list"
-                android:orientation="vertical"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:paddingLeft="@dimen/detail_update_section_side_padding"
-                android:paddingRight="@dimen/detail_update_section_side_padding" />
-        </LinearLayout>
-
-    </ScrollView>
+        android:background="@color/background_social_updates"
+        android:divider="@null"/>
 
     <View
         android:id="@+id/alpha_overlay"
diff --git a/res/layout-sw580dp/updates_header_contact.xml b/res/layout-sw580dp/updates_header_contact.xml
new file mode 100644
index 0000000..2f2177f
--- /dev/null
+++ b/res/layout-sw580dp/updates_header_contact.xml
@@ -0,0 +1,35 @@
+<?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.
+-->
+
+<!--
+  This is a header entry in the contact updates list.
+  Add a first item that gives us enough space to show the carousel
+-->
+<view
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:ex="http://schemas.android.com/apk/res/com.android.contacts"
+    class="com.android.contacts.widget.ProportionalLayout"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    ex:ratio="0.66"
+    ex:direction="widthToHeight">
+
+    <!-- Put a dummy view here because the ProportionalLayout requires one -->
+    <FrameLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+
+</view>
diff --git a/res/layout-w470dp/contact_detail_updates_fragment.xml b/res/layout-w470dp/contact_detail_updates_fragment.xml
index 0c8380c..92ddd8c 100644
--- a/res/layout-w470dp/contact_detail_updates_fragment.xml
+++ b/res/layout-w470dp/contact_detail_updates_fragment.xml
@@ -14,51 +14,21 @@
      limitations under the License.
 -->
 
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:ex="http://schemas.android.com/apk/res/com.android.contacts"
     android:id="@+id/contact_detail_updates_fragment"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_height="match_parent"
+    android:orientation="vertical">
 
-    <ScrollView
+    <include
+        android:id="@+id/title"
+        layout="@layout/contact_detail_kind_title_entry_view" />
+
+    <ListView android:id="@android:id/list"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:background="@color/background_social_updates">
+        android:layout_height="wrap_content"
+        android:background="@color/background_social_updates"
+        android:divider="@null"/>
 
-        <LinearLayout
-            android:orientation="vertical"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:paddingTop="@dimen/detail_update_section_top_padding">
-
-            <include
-                android:id="@+id/title"
-                layout="@layout/contact_detail_kind_title_entry_view" />
-
-            <LinearLayout
-                android:id="@+id/update_list"
-                android:orientation="vertical"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:paddingLeft="@dimen/detail_update_section_side_padding"
-                android:paddingRight="@dimen/detail_update_section_side_padding" />
-        </LinearLayout>
-
-    </ScrollView>
-
-    <View
-        android:id="@+id/alpha_overlay"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:background="@android:color/black"
-        android:alpha=".50"
-        android:visibility="gone"/>
-
-    <View
-        android:id="@+id/touch_intercept_overlay"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:background="?android:attr/selectableItemBackground"
-        android:visibility="gone"/>
-
-</FrameLayout>
+</LinearLayout>
diff --git a/res/layout-w470dp/updates_header_contact.xml b/res/layout-w470dp/updates_header_contact.xml
new file mode 100644
index 0000000..da63d20
--- /dev/null
+++ b/res/layout-w470dp/updates_header_contact.xml
@@ -0,0 +1,24 @@
+<?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.
+-->
+
+<!--
+  This is a header entry in the contact updates list.
+  This is empty because there is no header in this case.
+-->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="0dip"/>
diff --git a/res/layout/contact_detail_updates_fragment.xml b/res/layout/contact_detail_updates_fragment.xml
index 95eb0a5..2393ace 100644
--- a/res/layout/contact_detail_updates_fragment.xml
+++ b/res/layout/contact_detail_updates_fragment.xml
@@ -14,64 +14,17 @@
      limitations under the License.
 -->
 
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:ex="http://schemas.android.com/apk/res/com.android.contacts"
     android:id="@+id/contact_detail_updates_fragment"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
-    <ScrollView
+    <ListView android:id="@android:id/list"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:background="@color/background_social_updates">
-
-        <LinearLayout
-            android:orientation="vertical"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:paddingTop="@dimen/detail_update_section_top_padding">
-
-            <!-- Add a first item that gives us enough space to show the carousel -->
-            <view
-                class="com.android.contacts.widget.ProportionalLayout"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                ex:ratio="0.5"
-                ex:direction="widthToHeight">
-
-                <!-- Put a dummy view here because the ProportionalLayout requires one -->
-                <View
-                    android:layout_width="match_parent"
-                    android:layout_height="match_parent" />
-
-            </view>
-
-            <include
-                android:id="@+id/title"
-                layout="@layout/contact_detail_kind_title_entry_view" />
-
-            <LinearLayout
-                android:id="@+id/update_list"
-                android:orientation="vertical"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content" />
-        </LinearLayout>
-
-    </ScrollView>
-
-    <View
-        android:id="@+id/alpha_overlay"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:background="@android:color/black"
-        android:alpha=".50"
-        android:visibility="gone"/>
-
-    <View
-        android:id="@+id/touch_intercept_overlay"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:background="@android:color/transparent"
-        android:visibility="gone"/>
+        android:background="@color/background_social_updates"
+        android:divider="@null"/>
 
 </FrameLayout>
diff --git a/res/layout/updates_header_contact.xml b/res/layout/updates_header_contact.xml
new file mode 100644
index 0000000..d401f05
--- /dev/null
+++ b/res/layout/updates_header_contact.xml
@@ -0,0 +1,35 @@
+<?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.
+-->
+
+<!--
+  This is a header entry in the contact updates list.
+  Add a first item that gives us enough space to show the carousel
+-->
+<view
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:ex="http://schemas.android.com/apk/res/com.android.contacts"
+    class="com.android.contacts.widget.ProportionalLayout"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    ex:ratio="0.5"
+    ex:direction="widthToHeight">
+
+    <!-- Put a dummy view here because the ProportionalLayout requires one -->
+    <FrameLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+
+</view>
diff --git a/src/com/android/contacts/activities/ContactDetailActivity.java b/src/com/android/contacts/activities/ContactDetailActivity.java
index d888dbe..53c7f5e 100644
--- a/src/com/android/contacts/activities/ContactDetailActivity.java
+++ b/src/com/android/contacts/activities/ContactDetailActivity.java
@@ -154,6 +154,7 @@
 
         mDetailFragment.setListener(mFragmentListener);
         mDetailFragment.setVerticalScrollListener(mVerticalScrollListener);
+        mUpdatesFragment.setVerticalScrollListener(mVerticalScrollListener);
         mDetailFragment.setData(mLookupUri, mContactData);
         mUpdatesFragment.setData(mLookupUri, mContactData);
 
diff --git a/src/com/android/contacts/detail/ContactDetailDisplayUtils.java b/src/com/android/contacts/detail/ContactDetailDisplayUtils.java
index 7144dfb..e88e5e8 100644
--- a/src/com/android/contacts/detail/ContactDetailDisplayUtils.java
+++ b/src/com/android/contacts/detail/ContactDetailDisplayUtils.java
@@ -263,8 +263,7 @@
         }
     }
 
-    @VisibleForTesting
-    static void addStreamItemToContainer(LayoutInflater inflater, Context context,
+    public static View addStreamItemToContainer(LayoutInflater inflater, Context context,
             StreamItemEntry streamItem, LinearLayout streamContainer,
             View.OnClickListener listener) {
         View oneColumnView = inflater.inflate(R.layout.stream_item_one_column,
@@ -336,7 +335,11 @@
             }
         }
 
-        streamContainer.addView(oneColumnView);
+        if (streamContainer != null) {
+            streamContainer.addView(oneColumnView);
+        }
+
+        return oneColumnView;
     }
 
     @VisibleForTesting
@@ -426,4 +429,4 @@
         }
     }
 
-}
\ No newline at end of file
+}
diff --git a/src/com/android/contacts/detail/ContactDetailLayoutController.java b/src/com/android/contacts/detail/ContactDetailLayoutController.java
index 3fc4c31..7abe76e 100644
--- a/src/com/android/contacts/detail/ContactDetailLayoutController.java
+++ b/src/com/android/contacts/detail/ContactDetailLayoutController.java
@@ -116,6 +116,7 @@
 
         mDetailFragment.setListener(mContactDetailFragmentListener);
         mDetailFragment.setVerticalScrollListener(mVerticalScrollListener);
+        mUpdatesFragment.setVerticalScrollListener(mVerticalScrollListener);
 
         switch (mLayoutMode) {
             case VIEW_PAGER_AND_CAROUSEL: {
diff --git a/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java b/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
index d668429..308254f 100644
--- a/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
@@ -21,7 +21,7 @@
 import com.android.contacts.activities.ContactDetailActivity.FragmentKeyListener;
 import com.android.contacts.util.StreamItemEntry;
 
-import android.app.Fragment;
+import android.app.ListFragment;
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
@@ -30,10 +30,10 @@
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
-import android.widget.LinearLayout;
+import android.widget.AbsListView.OnScrollListener;
 import android.widget.TextView;
 
-public class ContactDetailUpdatesFragment extends Fragment
+public class ContactDetailUpdatesFragment extends ListFragment
         implements FragmentKeyListener, ViewOverlay {
 
     private static final String TAG = "ContactDetailUpdatesFragment";
@@ -42,9 +42,7 @@
     private Uri mLookupUri;
 
     private LayoutInflater mInflater;
-
-    // The linear layout that contains all the stream items.
-    private LinearLayout mStreamContainer;
+    private StreamItemAdapter mStreamItemAdapter;
 
     /**
      * This optional view adds an alpha layer over the entire fragment.
@@ -57,12 +55,14 @@
      */
     private View mTouchInterceptLayer;
 
+    private OnScrollListener mVerticalScrollListener;
+
     /**
      * Listener on clicks on a stream item.
      * <p>
      * It assumes the view has a tag of type {@link StreamItemEntry} associated with it.
      */
-    private View.OnClickListener mStreamItemClickListener = new OnClickListener() {
+    private View.OnClickListener mStreamItemClickListener = new View.OnClickListener() {
         @Override
         public void onClick(View view) {
             StreamItemEntry streamItemEntry = (StreamItemEntry) view.getTag();
@@ -90,17 +90,8 @@
                 false);
 
         TextView titleTextView = (TextView) rootView.findViewById(R.id.kind);
-        titleTextView.setText(getString(R.string.recent_updates).toUpperCase());
-
-        mStreamContainer = (LinearLayout) rootView.findViewById(R.id.update_list);
-
-        // It is possible that the contact data was set to the fragment when it was first attached
-        // to the activity, but before this method was called because the fragment was not
-        // visible on screen yet (i.e. using a {@link ViewPager}), so display the data if we already
-        // have it.
-        if (mContactData != null) {
-            ContactDetailDisplayUtils.showSocialStreamItems(inflater, getActivity(), mContactData,
-                    mStreamContainer, mStreamItemClickListener);
+        if (titleTextView != null) {
+            titleTextView.setText(getString(R.string.recent_updates).toUpperCase());
         }
 
         mAlphaLayer = rootView.findViewById(R.id.alpha_overlay);
@@ -109,14 +100,29 @@
         return rootView;
     }
 
+    @Override
+    public void onViewCreated(View view, Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+        mStreamItemAdapter = new StreamItemAdapter(getActivity(), mStreamItemClickListener);
+        setListAdapter(mStreamItemAdapter);
+        getListView().setOnScrollListener(mVerticalScrollListener);
+
+        // It is possible that the contact data was set to the fragment when it was first attached
+        // to the activity, but before this method was called because the fragment was not
+        // visible on screen yet (i.e. using a {@link ViewPager}), so display the data if we already
+        // have it.
+        if (mContactData != null) {
+            mStreamItemAdapter.setStreamItems(mContactData.getStreamItems());
+        }
+    }
+
     public void setData(Uri lookupUri, ContactLoader.Result result) {
         if (result == null) {
             return;
         }
         mLookupUri = lookupUri;
         mContactData = result;
-        ContactDetailDisplayUtils.showSocialStreamItems(mInflater, getActivity(), mContactData,
-                mStreamContainer, mStreamItemClickListener);
+        mStreamItemAdapter.setStreamItems(mContactData.getStreamItems());
     }
 
     @Override
@@ -152,4 +158,9 @@
     public boolean handleKeyDown(int keyCode) {
         return false;
     }
+
+    public void setVerticalScrollListener(OnScrollListener listener) {
+        mVerticalScrollListener = listener;
+    }
+
 }
diff --git a/src/com/android/contacts/detail/StreamItemAdapter.java b/src/com/android/contacts/detail/StreamItemAdapter.java
new file mode 100644
index 0000000..d8f4a81
--- /dev/null
+++ b/src/com/android/contacts/detail/StreamItemAdapter.java
@@ -0,0 +1,93 @@
+/*
+ * 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
+ */
+
+package com.android.contacts.detail;
+
+import com.android.contacts.R;
+import com.android.contacts.util.StreamItemEntry;
+import com.google.android.collect.Lists;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+
+import java.util.List;
+
+/**
+ * List adapter for stream items of a given contact.
+ */
+public class StreamItemAdapter extends BaseAdapter {
+    private static final int ITEM_VIEW_TYPE_HEADER = 0;
+    private static final int ITEM_VIEW_TYPE_STREAM_ITEM = 1;
+
+    private final Context mContext;
+    private final View.OnClickListener mListener;
+    private final LayoutInflater mInflater;
+
+    private List<StreamItemEntry> mStreamItems;
+
+    public StreamItemAdapter(Context context, View.OnClickListener listener) {
+        mContext = context;
+        mListener = listener;
+        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        mStreamItems = Lists.newArrayList();
+    }
+
+    @Override
+    public int getCount() {
+        return mStreamItems.size() + 1;
+    }
+
+    @Override
+    public Object getItem(int position) {
+        if (position == 0) {
+            return null;
+        }
+        return mStreamItems.get(position - 1);
+    }
+
+    @Override
+    public long getItemId(int position) {
+        if (position == 0) {
+            return -1;
+        }
+        return position - 1;
+    }
+
+    @Override
+    public View getView(int position, View convertView, ViewGroup parent) {
+        if (position == 0) {
+            return mInflater.inflate(R.layout.updates_header_contact, null);
+        }
+        return ContactDetailDisplayUtils.addStreamItemToContainer(
+                mInflater, mContext, (StreamItemEntry) getItem(position), null, mListener);
+    }
+
+    @Override
+    public int getItemViewType(int position) {
+        if (position == 0) {
+            return ITEM_VIEW_TYPE_HEADER;
+        }
+        return ITEM_VIEW_TYPE_STREAM_ITEM;
+    }
+
+    public void setStreamItems(List<StreamItemEntry> streamItems) {
+        mStreamItems = streamItems;
+        notifyDataSetChanged();
+    }
+}