Merge "Move call shortcut cards to their own list"
diff --git a/res/layout/call_log_list_item.xml b/res/layout/call_log_list_item.xml
index a33ec7d..953efc4 100644
--- a/res/layout/call_log_list_item.xml
+++ b/res/layout/call_log_list_item.xml
@@ -38,6 +38,7 @@
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
+        android:baselineAligned="false"
         android:orientation="horizontal"
         android:gravity="center_vertical"
         >
@@ -48,7 +49,6 @@
             android:layout_width="0dp"
             android:layout_weight="1"
             android:layout_height="wrap_content"
-            android:layout_centerVertical="true"
             android:padding="@dimen/call_log_outer_margin"
             android:orientation="horizontal"
             android:gravity="center_vertical"
diff --git a/res/layout/lists_fragment.xml b/res/layout/lists_fragment.xml
index 740dc2a..6ed0f85 100644
--- a/res/layout/lists_fragment.xml
+++ b/res/layout/lists_fragment.xml
@@ -19,7 +19,16 @@
     android:layout_height="match_parent"
     android:paddingTop="?android:attr/actionBarSize"
     android:orientation="vertical"
+    android:animateLayoutChanges="true"
     android:id="@+id/lists_frame">
+    <ListView
+        android:id="@+id/shortcut_card_list"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="@color/actionbar_background_color"
+        android:clipToPadding="false"
+        android:fadingEdge="none"
+        android:divider="@null" />
     <com.android.dialer.list.ViewPagerTabs
         android:id="@+id/lists_pager_header"
         android:layout_width="match_parent"
diff --git a/res/layout/phone_favorites_fragment.xml b/res/layout/phone_favorites_fragment.xml
index 5e9e3bb..89a9f73 100644
--- a/res/layout/phone_favorites_fragment.xml
+++ b/res/layout/phone_favorites_fragment.xml
@@ -35,6 +35,7 @@
             android:id="@+id/contact_tile_list"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
+            android:paddingTop="@dimen/favorites_row_top_padding"
             android:numColumns="@integer/contact_tile_column_count_in_favorites"
             android:clipToPadding="false"
             android:fadingEdge="none"
diff --git a/src/com/android/dialer/list/ListsFragment.java b/src/com/android/dialer/list/ListsFragment.java
index 5132727..3144b86 100644
--- a/src/com/android/dialer/list/ListsFragment.java
+++ b/src/com/android/dialer/list/ListsFragment.java
@@ -1,19 +1,34 @@
 package com.android.dialer.list;
 
-import android.app.Activity;
+import android.animation.LayoutTransition;
 import android.app.Fragment;
 import android.app.FragmentManager;
+import android.app.LoaderManager;
+import android.content.Context;
+import android.content.CursorLoader;
+import android.content.Loader;
+import android.content.SharedPreferences;
+import android.database.Cursor;
+import android.net.Uri;
 import android.os.Bundle;
+import android.provider.CallLog;
 import android.support.v13.app.FragmentPagerAdapter;
 import android.support.v4.view.ViewPager;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.LinearLayout;
+import android.widget.ListView;
 
-import com.android.contacts.common.list.OnPhoneNumberPickerActionListener;
+import com.android.contacts.common.GeoUtil;
+import com.android.dialer.DialtactsActivity;
 import com.android.dialer.R;
+import com.android.dialer.calllog.CallLogAdapter;
 import com.android.dialer.calllog.CallLogFragment;
+import com.android.dialer.calllog.CallLogQuery;
 import com.android.dialer.calllog.CallLogQueryHandler;
+import com.android.dialer.calllog.ContactInfoHelper;
+import com.android.dialerbind.ObjectFactory;
 
 /**
  * Fragment that is used as the main screen of the Dialer.
@@ -23,7 +38,23 @@
  * ViewPager containing the lists up above the shortcut cards and pin it against the top of the
  * screen.
  */
-public class ListsFragment extends Fragment {
+public class ListsFragment extends Fragment implements CallLogQueryHandler.Listener,
+        CallLogAdapter.CallFetcher {
+
+    private static final int TAB_INDEX_SPEED_DIAL = 0;
+    private static final int TAB_INDEX_RECENTS = 1;
+    private static final int TAB_INDEX_ALL_CONTACTS = 2;
+
+    private static final int TAB_INDEX_COUNT = 3;
+
+    // TODO: Replace with a date limit (e.g. 2 weeks)
+    private static final int MAX_ENTRIES = 20;
+
+    private static final String KEY_LAST_DISMISSED_CALL_SHORTCUT_DATE =
+            "key_last_dismissed_call_shortcut_date";
+
+    // Used with LoaderManager
+    private static int MISSED_CALL_LOADER = 1;
 
     private ViewPager mViewPager;
     private ViewPagerAdapter mViewPagerAdapter;
@@ -31,16 +62,43 @@
     private CallLogFragment mRecentsFragment;
     private AllContactsFragment mAllContactsFragment;
 
-    private static final int TAB_INDEX_SPEED_DIAL = 0;
-    private static final int TAB_INDEX_RECENTS = 1;
-    private static final int TAB_INDEX_ALL_CONTACTS = 2;
-
     private String[] mTabTitles;
 
-    private static final int TAB_INDEX_COUNT = 3;
+    private PhoneFavoriteMergedAdapter mMergedAdapter;
+    private CallLogAdapter mCallLogAdapter;
+    private CallLogQueryHandler mCallLogQueryHandler;
 
-    // TODO: Replace with a date limit (e.g. 2 weeks)
-    private static final int MAX_ENTRIES = 20;
+    /**
+     * Call shortcuts older than this date (persisted in shared preferences) will not show up in
+     * at the top of the screen
+     */
+    private long mLastCallShortcutDate = 0;
+
+    /**
+     * The date of the current call shortcut that is showing on screen.
+     */
+    private long mCurrentCallShortcutDate = 0;
+
+    private class MissedCallLogLoaderListener implements LoaderManager.LoaderCallbacks<Cursor> {
+
+        @Override
+        public Loader<Cursor> onCreateLoader(int id, Bundle args) {
+            final Uri uri = CallLog.Calls.CONTENT_URI;
+            final String[] projection = new String[] {CallLog.Calls.TYPE};
+            final String selection = CallLog.Calls.TYPE + " = " + CallLog.Calls.MISSED_TYPE +
+                    " AND " + CallLog.Calls.IS_READ + " = 0";
+            return new CursorLoader(getActivity(), uri, projection, selection, null, null);
+        }
+
+        @Override
+        public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor data) {
+            mCallLogAdapter.setMissedCalls(data);
+        }
+
+        @Override
+        public void onLoaderReset(Loader<Cursor> cursorLoader) {
+        }
+    }
 
     public class ViewPagerAdapter extends FragmentPagerAdapter {
         public ViewPagerAdapter(FragmentManager fm) {
@@ -76,6 +134,45 @@
     }
 
     @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mCallLogQueryHandler = new CallLogQueryHandler(getActivity().getContentResolver(),
+                this, 1);
+        final String currentCountryIso = GeoUtil.getCurrentCountryIso(getActivity());
+        mCallLogAdapter = ObjectFactory.newCallLogAdapter(getActivity(), this,
+                new ContactInfoHelper(getActivity(), currentCountryIso), false, false);
+
+        mMergedAdapter = new PhoneFavoriteMergedAdapter(getActivity(), this, null,
+                mCallLogAdapter, null, null);
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        getLoaderManager().initLoader(MISSED_CALL_LOADER, null, new MissedCallLogLoaderListener());
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        final SharedPreferences prefs = getActivity().getSharedPreferences(
+                DialtactsActivity.SHARED_PREFS_NAME, Context.MODE_PRIVATE);
+        mLastCallShortcutDate = prefs.getLong(KEY_LAST_DISMISSED_CALL_SHORTCUT_DATE, 0);
+
+        fetchCalls();
+        mCallLogAdapter.setLoading(true);
+    }
+
+    @Override
+    public void onPause() {
+        // Wipe the cache to refresh the call shortcut item. This is not that expensive because
+        // it only contains one item.
+        mCallLogAdapter.invalidateCache();
+        super.onPause();
+    }
+
+    @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
             Bundle savedInstanceState) {
         final View parentView = inflater.inflate(R.layout.lists_fragment, container, false);
@@ -91,6 +188,47 @@
 
         ViewPagerTabs tabs = (ViewPagerTabs) parentView.findViewById(R.id.lists_pager_header);
         tabs.setViewPager(mViewPager);
+
+        final ListView shortcutCardsListView =
+                (ListView) parentView.findViewById(R.id.shortcut_card_list);
+        shortcutCardsListView.setAdapter(mMergedAdapter);
+
+        LayoutTransition transition = ((LinearLayout) parentView).getLayoutTransition();
+        // Turns on animations for all types of layout changes so that they occur for
+        // height changes.
+        transition.enableTransitionType(LayoutTransition.CHANGING);
         return parentView;
     }
+
+    @Override
+    public void onVoicemailStatusFetched(Cursor statusCursor) {
+        // no-op
+    }
+
+    @Override
+    public void onCallsFetched(Cursor cursor) {
+        mCallLogAdapter.setLoading(false);
+
+        // Save the date of the most recent call log item
+        if (cursor != null && cursor.moveToFirst()) {
+            mCurrentCallShortcutDate = cursor.getLong(CallLogQuery.DATE);
+        }
+
+        mCallLogAdapter.changeCursor(cursor);
+        mMergedAdapter.notifyDataSetChanged();
+    }
+
+    @Override
+    public void fetchCalls() {
+        mCallLogQueryHandler.fetchCalls(CallLogQueryHandler.CALL_TYPE_ALL, mLastCallShortcutDate);
+    }
+
+    public void dismissShortcut(View view) {
+        mLastCallShortcutDate = mCurrentCallShortcutDate;
+        final SharedPreferences prefs = view.getContext().getSharedPreferences(
+                DialtactsActivity.SHARED_PREFS_NAME, Context.MODE_PRIVATE);
+        prefs.edit().putLong(KEY_LAST_DISMISSED_CALL_SHORTCUT_DATE, mLastCallShortcutDate)
+                .apply();
+        fetchCalls();
+    }
 }
diff --git a/src/com/android/dialer/list/PhoneFavoriteFragment.java b/src/com/android/dialer/list/PhoneFavoriteFragment.java
index ed6b5c8..05e2d44 100644
--- a/src/com/android/dialer/list/PhoneFavoriteFragment.java
+++ b/src/com/android/dialer/list/PhoneFavoriteFragment.java
@@ -21,25 +21,20 @@
 import android.app.Activity;
 import android.app.Fragment;
 import android.app.LoaderManager;
-import android.content.Context;
 import android.content.CursorLoader;
 import android.content.Loader;
-import android.content.SharedPreferences;
 import android.database.Cursor;
 import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Bundle;
-import android.provider.CallLog;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.view.View.OnClickListener;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
 import android.widget.AbsListView;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemClickListener;
-import android.widget.Button;
 import android.widget.ImageView;
 import android.widget.ListView;
 import android.widget.RelativeLayout;
@@ -47,17 +42,9 @@
 
 import com.android.contacts.common.ContactPhotoManager;
 import com.android.contacts.common.ContactTileLoaderFactory;
-import com.android.contacts.common.GeoUtil;
-import com.android.contacts.common.list.ContactEntry;
 import com.android.contacts.common.list.ContactTileView;
 import com.android.contacts.common.list.OnPhoneNumberPickerActionListener;
-import com.android.dialer.DialtactsActivity;
 import com.android.dialer.R;
-import com.android.dialer.calllog.CallLogAdapter;
-import com.android.dialer.calllog.CallLogQuery;
-import com.android.dialer.calllog.CallLogQueryHandler;
-import com.android.dialer.calllog.ContactInfoHelper;
-import com.android.dialerbind.ObjectFactory;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -71,7 +58,6 @@
  * A contact filter header is also inserted between those adapters' results.
  */
 public class PhoneFavoriteFragment extends Fragment implements OnItemClickListener,
-        CallLogQueryHandler.Listener, CallLogAdapter.CallFetcher,
         PhoneFavoritesTileAdapter.OnDataSetChangedForAnimationListener {
 
     /**
@@ -92,36 +78,11 @@
      * Used with LoaderManager.
      */
     private static int LOADER_ID_CONTACT_TILE = 1;
-    private static int MISSED_CALL_LOADER = 2;
-
-    private static final String KEY_LAST_DISMISSED_CALL_SHORTCUT_DATE =
-            "key_last_dismissed_call_shortcut_date";
 
     public interface HostInterface {
         public void setDragDropController(DragDropController controller);
     }
 
-    private class MissedCallLogLoaderListener implements LoaderManager.LoaderCallbacks<Cursor> {
-
-        @Override
-        public Loader<Cursor> onCreateLoader(int id, Bundle args) {
-            final Uri uri = CallLog.Calls.CONTENT_URI;
-            final String[] projection = new String[] {CallLog.Calls.TYPE};
-            final String selection = CallLog.Calls.TYPE + " = " + CallLog.Calls.MISSED_TYPE +
-                    " AND " + CallLog.Calls.IS_READ + " = 0";
-            return new CursorLoader(getActivity(), uri, projection, selection, null, null);
-        }
-
-        @Override
-        public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor data) {
-            mCallLogAdapter.setMissedCalls(data);
-        }
-
-        @Override
-        public void onLoaderReset(Loader<Cursor> cursorLoader) {
-        }
-    }
-
     private class ContactTileLoaderListener implements LoaderManager.LoaderCallbacks<Cursor> {
         @Override
         public CursorLoader onCreateLoader(int id, Bundle args) {
@@ -182,12 +143,8 @@
     private OnPhoneNumberPickerActionListener mPhoneNumberPickerActionListener;
 
     private OnListFragmentScrolledListener mActivityScrollListener;
-    private PhoneFavoriteMergedAdapter mAdapter;
     private PhoneFavoritesTileAdapter mContactTileAdapter;
 
-    private CallLogAdapter mCallLogAdapter;
-    private CallLogQueryHandler mCallLogQueryHandler;
-
     private View mParentView;
 
     private PhoneFavoriteListView mListView;
@@ -205,17 +162,6 @@
      */
     private View mEmptyView;
 
-    /**
-     * Call shortcuts older than this date (persisted in shared preferences) will not show up in
-     * at the top of the screen
-     */
-    private long mLastCallShortcutDate = 0;
-
-    /**
-     * The date of the current call shortcut that is showing on screen.
-     */
-    private long mCurrentCallShortcutDate = 0;
-
     private final ContactTileView.Listener mContactTileAdapterListener =
             new ContactTileAdapterListener();
     private final LoaderManager.LoaderCallbacks<Cursor> mContactTileLoaderListener =
@@ -241,23 +187,12 @@
         super.onCreate(savedState);
 
         mAnimationDuration = getResources().getInteger(R.integer.fade_duration);
-        mCallLogQueryHandler = new CallLogQueryHandler(getActivity().getContentResolver(),
-                this, 1);
-        final String currentCountryIso = GeoUtil.getCurrentCountryIso(getActivity());
-        mCallLogAdapter = ObjectFactory.newCallLogAdapter(getActivity(), this,
-                new ContactInfoHelper(getActivity(), currentCountryIso), false, false);
     }
 
     @Override
     public void onResume() {
         super.onResume();
-        final SharedPreferences prefs = getActivity().getSharedPreferences(
-                DialtactsActivity.SHARED_PREFS_NAME, Context.MODE_PRIVATE);
 
-        mLastCallShortcutDate = prefs.getLong(KEY_LAST_DISMISSED_CALL_SHORTCUT_DATE, 0);
-
-        fetchCalls();
-        mCallLogAdapter.setLoading(true);
         getLoaderManager().getLoader(LOADER_ID_CONTACT_TILE).forceLoad();
     }
 
@@ -286,12 +221,6 @@
         mTileInteractionTeaserView = (TileInteractionTeaserView) inflater.inflate(
                 R.layout.tile_interactions_teaser_view, mListView, false);
 
-        mAdapter = new PhoneFavoriteMergedAdapter(getActivity(), this, mContactTileAdapter,
-                mCallLogAdapter, mPhoneFavoritesMenu, mTileInteractionTeaserView);
-
-
-        mTileInteractionTeaserView.setAdapter(mAdapter);
-
         mListView.setAdapter(mContactTileAdapter);
 
         mListView.setOnScrollListener(mScrollListener);
@@ -352,7 +281,6 @@
         // This method call implicitly assures ContactTileLoaderListener's onLoadFinished() will
         // be called, on which we'll check if "all" contacts should be reloaded again or not.
         getLoaderManager().initLoader(LOADER_ID_CONTACT_TILE, null, mContactTileLoaderListener);
-        getLoaderManager().initLoader(MISSED_CALL_LOADER, null, new MissedCallLogLoaderListener());
     }
 
     /**
@@ -370,37 +298,6 @@
         }
     }
 
-    @Override
-    public void onVoicemailStatusFetched(Cursor statusCursor) {
-        // no-op
-    }
-
-    @Override
-    public void onCallsFetched(Cursor cursor) {
-        mCallLogAdapter.setLoading(false);
-
-        // Save the date of the most recent call log item
-        if (cursor != null && cursor.moveToFirst()) {
-            mCurrentCallShortcutDate = cursor.getLong(CallLogQuery.DATE);
-        }
-
-        mCallLogAdapter.changeCursor(cursor);
-        mAdapter.notifyDataSetChanged();
-    }
-
-    @Override
-    public void fetchCalls() {
-        mCallLogQueryHandler.fetchCalls(CallLogQueryHandler.CALL_TYPE_ALL, mLastCallShortcutDate);
-    }
-
-    @Override
-    public void onPause() {
-        // Wipe the cache to refresh the call shortcut item. This is not that expensive because
-        // it only contains one item.
-        mCallLogAdapter.invalidateCache();
-        super.onPause();
-    }
-
     /**
      * Cache the current view offsets into memory. Once a relayout of views in the ListView
      * has happened due to a dataset change, the cached offsets are used to create animations
@@ -520,15 +417,4 @@
     public void cacheOffsetsForDatasetChange() {
         saveOffsets(0);
     }
-
-    public void dismissShortcut(View view) {
-        final int height = ((View) view.getParent()).getHeight();
-        saveOffsets(height);
-        mLastCallShortcutDate = mCurrentCallShortcutDate;
-        final SharedPreferences prefs = view.getContext().getSharedPreferences(
-                DialtactsActivity.SHARED_PREFS_NAME, Context.MODE_PRIVATE);
-        prefs.edit().putLong(KEY_LAST_DISMISSED_CALL_SHORTCUT_DATE, mLastCallShortcutDate)
-                .apply();
-        fetchCalls();
-    }
 }
diff --git a/src/com/android/dialer/list/PhoneFavoriteMergedAdapter.java b/src/com/android/dialer/list/PhoneFavoriteMergedAdapter.java
index e2b9bb2..03ff67e 100644
--- a/src/com/android/dialer/list/PhoneFavoriteMergedAdapter.java
+++ b/src/com/android/dialer/list/PhoneFavoriteMergedAdapter.java
@@ -55,7 +55,7 @@
     private final PhoneFavoritesTileAdapter mContactTileAdapter;
     private final CallLogAdapter mCallLogAdapter;
     private final View mPhoneFavoritesMenu;
-    private final PhoneFavoriteFragment mFragment;
+    private final ListsFragment mFragment;
     private final TileInteractionTeaserView mTileInteractionTeaserView;
 
     private final int mCallLogPadding;
@@ -100,7 +100,7 @@
     };
 
     public PhoneFavoriteMergedAdapter(Context context,
-            PhoneFavoriteFragment fragment,
+            ListsFragment fragment,
             PhoneFavoritesTileAdapter contactTileAdapter,
             CallLogAdapter callLogAdapter,
             View phoneFavoritesMenu,
@@ -113,11 +113,7 @@
         mCallLogAdapter = callLogAdapter;
         mObserver = new CustomDataSetObserver();
         mCallLogAdapter.registerDataSetObserver(mObserver);
-        mContactTileAdapter.registerDataSetObserver(mObserver);
         mPhoneFavoritesMenu = phoneFavoritesMenu;
-        // Temporary hack to hide the favorites menu because it is not being used.
-        // It should be removed from this adapter entirely eventually.
-        mPhoneFavoritesMenu.setVisibility(View.GONE);
         mTileInteractionTeaserView = tileInteractionTeaserView;
         mCallLogQueryHandler = new CallLogQueryHandler(mContext.getContentResolver(),
                 mCallLogQueryHandlerListener);
@@ -133,8 +129,7 @@
      */
     @Override
     public int getCount() {
-        return mContactTileAdapter.getCount() + mCallLogAdapter.getCount() + getTeaserViewCount()
-                + 1;
+        return mCallLogAdapter.getCount();
     }
 
     @Override
@@ -196,10 +191,7 @@
      */
     @Override
     public int getViewTypeCount() {
-        return (mContactTileAdapter.getViewTypeCount() +            /* Favorite and frequent */
-                mCallLogAdapter.getViewTypeCount() +                /* Recent call log */
-                getTeaserViewCount() +                              /* Teaser */
-                1);                                                 /* Favorites menu. */
+        return mCallLogAdapter.getViewTypeCount();
     }
 
     @Override
@@ -207,9 +199,7 @@
         final int callLogAdapterCount = mCallLogAdapter.getCount();
 
         if (position < callLogAdapterCount) {
-            // View type of the call log adapter is the last view type of the contact tile adapter
-            // + 1
-            return mContactTileAdapter.getViewTypeCount();
+            return 0;
         } else if (position == TILE_INTERACTION_TEASER_VIEW_POSITION + callLogAdapterCount &&
                 mTileInteractionTeaserView.getShouldDisplayInList()) {
             // View type of the teaser row is the last view type of the contact tile adapter +2
@@ -236,11 +226,7 @@
     public View getView(int position, View convertView, ViewGroup parent) {
         final int callLogAdapterCount = mCallLogAdapter.getCount();
 
-        // Get the view for the "teaser view" which describes how to re-arrange favorites.
-        if (mTileInteractionTeaserView.getShouldDisplayInList()
-                && position == TILE_INTERACTION_TEASER_VIEW_POSITION + callLogAdapterCount) {
-            return mTileInteractionTeaserView;
-        } else if (callLogAdapterCount > 0 && position < callLogAdapterCount) {
+        if (callLogAdapterCount > 0 && position < callLogAdapterCount) {
             // Handle case where we are requesting the view for the "most recent caller".
 
             final SwipeableCallLogRow wrapper;
@@ -281,7 +267,7 @@
 
     @Override
     public boolean areAllItemsEnabled() {
-        return mCallLogAdapter.areAllItemsEnabled() && mContactTileAdapter.areAllItemsEnabled();
+        return mCallLogAdapter.areAllItemsEnabled();
     }
 
     @Override