Adding "Speed Dial" title to dialer favorites list and moving "All Contacts" affordance.

Bug: 13080167
Change-Id: Id825ef4bfc9de5340d40cae8176bdc13fcfb3ccd
(cherry picked from commit 9a06657538802e0100dc65c6ae0713c996298e1b)
diff --git a/res/drawable/background_favorites_menu.xml b/res/drawable/background_favorites_menu.xml
new file mode 100644
index 0000000..fc2669b
--- /dev/null
+++ b/res/drawable/background_favorites_menu.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2014 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
+  -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="false">
+        <shape android:shape="rectangle" >
+            <solid android:color="@color/background_dialer_list_items" />
+        </shape>
+    </item>
+    <item android:state_pressed="true">
+        <shape android:shape="rectangle" >
+            <solid android:color="@color/favorites_menu_pressed_color" />
+        </shape>
+    </item>
+</selector>
\ No newline at end of file
diff --git a/res/layout/phone_favorites_menu.xml b/res/layout/phone_favorites_menu.xml
new file mode 100644
index 0000000..d8f2f32
--- /dev/null
+++ b/res/layout/phone_favorites_menu.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2014 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
+  -->
+
+<!-- The phone favorites menu appears on the main dialer screen above the favorite callers area,
+     and provides access to the All Contacts list. -->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:id="@+id/phone_favorites_menu"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:paddingLeft="@dimen/favorites_menu_margin"
+                android:paddingRight="@dimen/favorites_menu_margin"
+                android:paddingTop="@dimen/favorites_menu_margin"
+                android:paddingBottom="@dimen/favorites_menu_margin"
+                android:background="@drawable/background_favorites_menu"
+                android:addStatesFromChildren="true"
+        >
+    <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="@dimen/favorites_menu_speed_dial_height"
+            android:fontFamily="@string/favorites_menu_speed_dial_font_family"
+            android:text="@string/favorites_menu_speed_dial"
+            android:textSize="@dimen/favorites_menu_speed_dial_text_size"
+            android:textColor="@color/speed_dial_text_color"
+            android:layout_alignParentLeft="true"
+            android:layout_centerVertical="true"
+            android:gravity="center"
+        />
+    <TextView
+            android:id="@+id/all_contacts_button"
+            android:fontFamily="@string/favorites_menu_all_contacts_font_family"
+            android:layout_width="wrap_content"
+            android:layout_height="@dimen/favorites_menu_all_contacts_height"
+            android:paddingLeft="@dimen/favorites_menu_padding"
+            android:paddingRight="@dimen/favorites_menu_padding"
+            android:text="@string/favorites_menu_all_contacts"
+            android:textSize="@dimen/favorites_menu_all_contacts_text_size"
+            android:background="@color/all_contacts_button_color"
+            android:textColor="@color/all_contacts_button_text_color"
+            android:layout_alignParentRight="true"
+            android:layout_centerVertical="true"
+            android:gravity="center"
+            android:focusable="true"
+        />
+</RelativeLayout>
\ No newline at end of file
diff --git a/res/values/colors.xml b/res/values/colors.xml
index b2d4bc5..370bdfe 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -70,4 +70,17 @@
 
     <!-- Text color for no favorites message -->
     <color name="nofavorite_text_color">#777777</color>
+
+    <!-- Text color for the "speed dial" label in the favorites menu. -->
+    <color name="speed_dial_text_color">#555555</color>
+
+    <!-- Background color for the "All Contacts" button in the favorites menu. -->
+    <color name="all_contacts_button_color">#999999</color>
+
+    <!-- Background color for the favorites menu when pressed. -->
+    <color name="favorites_menu_pressed_color">#d6d6d6</color>
+
+    <!-- Text color for the "All Contacts" button above the favorite callers -->
+    <color name="all_contacts_button_text_color">#ffffff</color>
+
 </resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 9426987..3c856d2 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -83,4 +83,17 @@
     <!-- Padding for the tooltip -->
     <dimen name="dismiss_button_padding_start">20dip</dimen>
     <dimen name="dismiss_button_padding_end">28dip</dimen>
+
+    <!-- Margin around the favorites menu. -->
+    <dimen name="favorites_menu_margin">6dp</dimen>
+    <!-- Padding within the favorites menu. -->
+    <dimen name="favorites_menu_padding">4dp</dimen>
+    <!-- Text size for the "speed dial" text in the favorites menu. -->
+    <dimen name="favorites_menu_speed_dial_text_size">18sp</dimen>
+    <!-- Height of the speed dial TextView in the favorites menu. -->
+    <dimen name="favorites_menu_speed_dial_height">24dp</dimen>
+    <!-- Text size for the "All Contacts" text in the favorites menu. -->
+    <dimen name="favorites_menu_all_contacts_text_size">12sp</dimen>
+    <!-- Height of the all contacts Button in the favorites menu. -->
+    <dimen name="favorites_menu_all_contacts_height">24dp</dimen>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index e848341..2564cd7 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -719,4 +719,22 @@
 
     <!-- Content description for dismiss button on badge. [CHAR LIMIT=NONE] -->
     <string name="description_dismiss">Dismiss</string>
+
+    <!-- Header text displayed on the main dialer screen above the list of favorite phone numbers.
+         [CHAR LIMIT=21] -->
+    <string name="favorites_menu_speed_dial">Speed Dial</string>
+
+    <!-- Button text for the "all contacts" button displayed on the main dialer screen above the
+         list of favorite phone numbers.  Navigates the user to the "All Contacts" list.
+         This text represents the same action as the text in string "menu_allContacts".
+         [CHAR LIMIT=21] -->
+    <string name="favorites_menu_all_contacts">ALL CONTACTS</string>
+
+    <!-- The font-family to use for the "speed dial" label on the favorites menu.
+         Do not translate. -->
+    <string name="favorites_menu_speed_dial_font_family">sans-serif-light</string>
+
+    <!-- The font-family to use for the "all contacts" label on the favorites menu.
+         Do not translate. -->
+    <string name="favorites_menu_all_contacts_font_family">sans-serif</string>
 </resources>
diff --git a/src/com/android/dialer/list/PhoneFavoriteFragment.java b/src/com/android/dialer/list/PhoneFavoriteFragment.java
index 027674a..860f9dc 100644
--- a/src/com/android/dialer/list/PhoneFavoriteFragment.java
+++ b/src/com/android/dialer/list/PhoneFavoriteFragment.java
@@ -25,7 +25,6 @@
 import android.content.CursorLoader;
 import android.content.Loader;
 import android.content.SharedPreferences;
-import android.content.res.Resources;
 import android.database.Cursor;
 import android.graphics.Rect;
 import android.net.Uri;
@@ -40,6 +39,7 @@
 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;
@@ -195,8 +195,7 @@
 
     private PhoneFavoriteListView mListView;
 
-    private View mShowAllContactsButton;
-    private View mShowAllContactsInEmptyViewButton;
+    private View mPhoneFavoritesMenu;
     private View mContactTileFrame;
 
     private TileInteractionTeaserView mTileInteractionTeaserView;
@@ -288,14 +287,8 @@
 
         mEmptyView = mParentView.findViewById(R.id.phone_no_favorites_view);
 
-        mShowAllContactsInEmptyViewButton = mParentView.findViewById(
-                R.id.show_all_contact_button_in_nofav);
-        prepareAllContactsButton(mShowAllContactsInEmptyViewButton);
-
-        mShowAllContactsButton = inflater.inflate(R.layout.show_all_contact_button, mListView,
-                false);
-
-        prepareAllContactsButton(mShowAllContactsButton);
+        mPhoneFavoritesMenu = inflater.inflate(R.layout.phone_favorites_menu, mListView, false);
+        prepareFavoritesMenu(mPhoneFavoritesMenu);
 
         mContactTileFrame = mParentView.findViewById(R.id.contact_tile_frame);
 
@@ -303,7 +296,7 @@
                 R.layout.tile_interactions_teaser_view, mListView, false);
 
         mAdapter = new PhoneFavoriteMergedAdapter(getActivity(), this, mContactTileAdapter,
-                mCallLogAdapter, mShowAllContactsButton, mTileInteractionTeaserView);
+                mCallLogAdapter, mPhoneFavoritesMenu, mTileInteractionTeaserView);
 
         mTileInteractionTeaserView.setAdapter(mAdapter);
 
@@ -666,31 +659,17 @@
     }
 
     /**
-     * Returns a view that is laid out and styled to look like a regular contact, with the correct
-     * click behavior (to launch the all contacts activity when it is clicked).
+     * Prepares the favorites menu which contains the static label "Speed Dial" and the
+     * "All Contacts" button.  Taps anywhere in the view take the user to "All Contacts".
+     * This emulates how the headers in Play Store work.
      */
-    private View prepareAllContactsButton(View v) {
-        final ContactListItemView view = (ContactListItemView) v;
-        view.setOnClickListener(new OnClickListener() {
+    private void prepareFavoritesMenu(View favoritesMenu) {
+        // Set the onClick listener for the view to bring up the all contacts view.
+        favoritesMenu.setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View view) {
                 showAllContacts();
             }
         });
-
-        view.setPhotoPosition(ContactListItemView.PhotoPosition.LEFT);
-        final Resources resources = getResources();
-        view.setBackgroundResource(R.drawable.contact_list_item_background);
-
-        view.setPaddingRelative(
-                resources.getDimensionPixelSize(R.dimen.favorites_row_start_padding),
-                resources.getDimensionPixelSize(R.dimen.favorites_row_end_padding),
-                resources.getDimensionPixelSize(R.dimen.favorites_row_top_padding),
-                resources.getDimensionPixelSize(R.dimen.favorites_row_bottom_padding));
-
-        view.setDisplayName(resources.getString(R.string.show_all_contacts_button_text));
-        view.setDrawableResource(R.drawable.list_item_avatar_bg,
-                R.drawable.ic_menu_all_contacts_dk);
-        return view;
     }
 }
diff --git a/src/com/android/dialer/list/PhoneFavoriteMergedAdapter.java b/src/com/android/dialer/list/PhoneFavoriteMergedAdapter.java
index daba39e..1c871e8 100644
--- a/src/com/android/dialer/list/PhoneFavoriteMergedAdapter.java
+++ b/src/com/android/dialer/list/PhoneFavoriteMergedAdapter.java
@@ -49,12 +49,12 @@
 
     private static final String TAG = PhoneFavoriteMergedAdapter.class.getSimpleName();
 
-    private static final int TILE_INTERACTION_TEASER_VIEW_POSITION = 2;
+    private static final int TILE_INTERACTION_TEASER_VIEW_POSITION = 3;
     private static final int TILE_INTERACTION_TEASER_VIEW_ID = -2;
-    private static final int ALL_CONTACTS_BUTTON_ITEM_ID = -1;
+    private static final int FAVORITES_MENU_ITEM_ID = -3;
     private final PhoneFavoritesTileAdapter mContactTileAdapter;
     private final CallLogAdapter mCallLogAdapter;
-    private final View mShowAllContactsButton;
+    private final View mPhoneFavoritesMenu;
     private final PhoneFavoriteFragment mFragment;
     private final TileInteractionTeaserView mTileInteractionTeaserView;
 
@@ -103,7 +103,7 @@
             PhoneFavoriteFragment fragment,
             PhoneFavoritesTileAdapter contactTileAdapter,
             CallLogAdapter callLogAdapter,
-            View showAllContactsButton,
+            View phoneFavoritesMenu,
             TileInteractionTeaserView tileInteractionTeaserView) {
         final Resources resources = context.getResources();
         mContext = context;
@@ -114,20 +114,24 @@
         mObserver = new CustomDataSetObserver();
         mCallLogAdapter.registerDataSetObserver(mObserver);
         mContactTileAdapter.registerDataSetObserver(mObserver);
-        mShowAllContactsButton = showAllContactsButton;
+        mPhoneFavoritesMenu = phoneFavoritesMenu;
         mTileInteractionTeaserView = tileInteractionTeaserView;
         mCallLogQueryHandler = new CallLogQueryHandler(mContext.getContentResolver(),
                 mCallLogQueryHandlerListener);
     }
 
+    /**
+     * Determines the number of items in the adapter.
+     * mCallLogAdapter contains the item for the most recent caller.
+     * mContactTileAdapter contains the starred contacts.
+     * The +1 is to account for the presence of the favorites menu.
+     *
+     * @return Number of items in the adapter.
+     */
     @Override
     public int getCount() {
-        if (mContactTileAdapter.getCount() > 0) {
-            return mContactTileAdapter.getCount() + mCallLogAdapter.getCount() + 1 +
-                    getTeaserViewCount();
-        } else {
-            return mCallLogAdapter.getCount();
-        }
+        return mContactTileAdapter.getCount() + mCallLogAdapter.getCount() + getTeaserViewCount()
+                + 1;
     }
 
     @Override
@@ -151,9 +155,9 @@
      *
      * These are the ranges of IDs reserved for each item type.
      *
-     * -(N + 1) to -3: CallLogAdapterItems, where N is equal to the number of call log items
+     * -4 and lower: CallLogAdapterItems representing most recent call.
+     * -3: Favorites menu
      * -2: Teaser
-     * -1: All contacts button
      * 0 to (N -1): Rows of tiled contacts, where N is equal to the max rows of tiled contacts
      * N to infinity: Rows of regular contacts. Their item id is calculated by N + contact_id,
      * where contact_id is guaranteed to never be negative.
@@ -163,17 +167,19 @@
         final int callLogAdapterCount = mCallLogAdapter.getCount();
         if (position < callLogAdapterCount) {
             // Call log items are not animated, so reusing their position for IDs is fine.
-            return ALL_CONTACTS_BUTTON_ITEM_ID - 2 - position;
+            return FAVORITES_MENU_ITEM_ID - 1 - position;
         } else if (position == TILE_INTERACTION_TEASER_VIEW_POSITION + callLogAdapterCount &&
-                mTileInteractionTeaserView.getShouldDisplayInList()){
+                mTileInteractionTeaserView.getShouldDisplayInList()) {
             return TILE_INTERACTION_TEASER_VIEW_ID;
+        } else if (position == callLogAdapterCount) {
+            return FAVORITES_MENU_ITEM_ID;
         } else if (position < (callLogAdapterCount + mContactTileAdapter.getCount() +
-                getTeaserViewCount())) {
+                getTeaserViewCount() + 1)) {
             return mContactTileAdapter.getItemId(
                     getAdjustedFavoritePosition(position, callLogAdapterCount));
         } else {
-            // All contacts button
-            return ALL_CONTACTS_BUTTON_ITEM_ID;
+            // Default fallback.  We don't normally get here.
+            return FAVORITES_MENU_ITEM_ID;
         }
     }
 
@@ -182,12 +188,15 @@
         return true;
     }
 
+    /**
+     * Determine the number of view types present.
+     */
     @Override
     public int getViewTypeCount() {
         return (mContactTileAdapter.getViewTypeCount() +            /* Favorite and frequent */
                 mCallLogAdapter.getViewTypeCount() +                /* Recent call log */
                 getTeaserViewCount() +                              /* Teaser */
-                1);                                                 /* Show all contacts button. */
+                1);                                                 /* Favorites menu. */
     }
 
     @Override
@@ -200,60 +209,66 @@
             return mContactTileAdapter.getViewTypeCount();
         } 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 + 3
+            // View type of the teaser row is the last view type of the contact tile adapter +2
             return mContactTileAdapter.getViewTypeCount() + 2;
-        } else if (position < getCount() - 1) {
+        } else if (position == callLogAdapterCount) {
+            // View type of the favorites menu is last view type of contact tile adapter +3
+            return mContactTileAdapter.getViewTypeCount() + 3;
+        } else if (position < getCount()) {
             return mContactTileAdapter.getItemViewType(
                     getAdjustedFavoritePosition(position, callLogAdapterCount));
         } else {
-            // View type of the show all contact button is the last view type of the contact tile
-            // adapter + 2
-            return mContactTileAdapter.getViewTypeCount() + 1;
+            // Catch-all - we shouldn't get here but if we do use the same as the favorites menu.
+            return mContactTileAdapter.getViewTypeCount() + 3;
         }
     }
 
+    /**
+     * Determines the view for a specified position.
+     *
+     * @param position Position for which to retrieve view.
+     * @return view corresponding to position.
+     */
     @Override
     public View getView(int position, View convertView, ViewGroup parent) {
         final int callLogAdapterCount = mCallLogAdapter.getCount();
 
-        if ((position == getCount() - 1) && (mContactTileAdapter.getCount() > 0)) {
-            return mShowAllContactsButton;
-        }
+        // 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) {
+            // Handle case where we are requesting the view for the "most recent caller".
 
-        if (mTileInteractionTeaserView.getShouldDisplayInList())  {
-            if (position == TILE_INTERACTION_TEASER_VIEW_POSITION + callLogAdapterCount) {
-                return mTileInteractionTeaserView;
+            final SwipeableCallLogRow wrapper;
+            if (convertView == null) {
+                wrapper = new SwipeableCallLogRow(mContext);
+                wrapper.setOnItemSwipeListener(mCallLogOnItemSwipeListener);
+            } else {
+                wrapper = (SwipeableCallLogRow) convertView;
             }
+
+            // Special case wrapper view for the most recent call log item. This allows
+            // us to create a card-like effect for the more recent call log item in
+            // the PhoneFavoriteMergedAdapter, but keep the original look of the item in
+            // the CallLogAdapter.
+            final View view = mCallLogAdapter.getView(position, convertView == null ?
+                    null : wrapper.getChildAt(0), parent);
+            wrapper.removeAllViews();
+            final View callLogItem = view.findViewById(R.id.call_log_list_item);
+            // Reset the internal call log item view if it is being recycled
+            callLogItem.setTranslationX(0);
+            callLogItem.setAlpha(1);
+            wrapper.addView(view);
+            return wrapper;
+        } else if (position == callLogAdapterCount) {
+            // If position is just after the entries in the mCallLogAdapter (most recent call),
+            // return the favorites menu.
+            return mPhoneFavoritesMenu;
         }
 
-        if (callLogAdapterCount > 0) {
-            if (position == 0) {
-                final SwipeableCallLogRow wrapper;
-                if (convertView == null) {
-                    wrapper = new SwipeableCallLogRow(mContext);
-                    wrapper.setOnItemSwipeListener(mCallLogOnItemSwipeListener);
-                } else {
-                    wrapper = (SwipeableCallLogRow) convertView;
-                }
-
-                // Special case wrapper view for the most recent call log item. This allows
-                // us to create a card-like effect for the more recent call log item in
-                // the PhoneFavoriteMergedAdapter, but keep the original look of the item in
-                // the CallLogAdapter.
-                final View view = mCallLogAdapter.getView(position, convertView == null ?
-                        null : wrapper.getChildAt(0), parent);
-                wrapper.removeAllViews();
-                final View callLogItem = view.findViewById(R.id.call_log_list_item);
-                // Reset the internal call log item view if it is being recycled
-                callLogItem.setTranslationX(0);
-                callLogItem.setAlpha(1);
-                wrapper.addView(view);
-                return wrapper;
-            }
-        }
-
-        // Set position to the position of the actual favorite contact in the
-        // favorites adapter
+        // Set position to the position of the actual favorite contact in the favorites adapter.
+        // Adjusts based on the presence of other views, such as the favorites menu.
         position = getAdjustedFavoritePosition(position, callLogAdapterCount);
 
         // Favorites section
@@ -285,15 +300,26 @@
         }
     }
 
+    /**
+     * Determines the index into the mContactTileAdapter for the current position.
+     *
+     * @param position current position in the overall adapter.
+     * @param callLogAdapterCount number of entries in "last calls" list (ie 0 or 1).
+     * @return position in the mContactTileAdapter.
+     */
     private int getAdjustedFavoritePosition(int position, int callLogAdapterCount) {
         if (position - callLogAdapterCount > TILE_INTERACTION_TEASER_VIEW_POSITION &&
                 mTileInteractionTeaserView.getShouldDisplayInList()) {
-            return position - callLogAdapterCount - 1;
+            return position - callLogAdapterCount - 2;
         } else {
-            return position - callLogAdapterCount;
+            return position - callLogAdapterCount - 1;
         }
     }
 
+    /**
+     * Determines the number of teaser views visible.
+     * @return 1 or 0 depending on if the teaser view is showing.
+     */
     private int getTeaserViewCount() {
         return (mContactTileAdapter.getCount() > TILE_INTERACTION_TEASER_VIEW_POSITION &&
                 mTileInteractionTeaserView.getShouldDisplayInList() ? 1 : 0);