Adds tooltip for Dialer

Bug: 10916819
Change-Id: Ic18f982a6d478b165f576361cfec6edb8c6eb1c3
diff --git a/res/drawable-hdpi/ic_arrow.png b/res/drawable-hdpi/ic_arrow.png
new file mode 100644
index 0000000..8d0dfcd
--- /dev/null
+++ b/res/drawable-hdpi/ic_arrow.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_cancel_holo_light.png b/res/drawable-hdpi/ic_cancel_holo_light.png
new file mode 100644
index 0000000..d8cacb4
--- /dev/null
+++ b/res/drawable-hdpi/ic_cancel_holo_light.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_arrow.png b/res/drawable-mdpi/ic_arrow.png
new file mode 100644
index 0000000..96440a2
--- /dev/null
+++ b/res/drawable-mdpi/ic_arrow.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_cancel_holo_light.png b/res/drawable-mdpi/ic_cancel_holo_light.png
new file mode 100644
index 0000000..56705c3
--- /dev/null
+++ b/res/drawable-mdpi/ic_cancel_holo_light.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_arrow.png b/res/drawable-xhdpi/ic_arrow.png
new file mode 100644
index 0000000..889c33f
--- /dev/null
+++ b/res/drawable-xhdpi/ic_arrow.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_cancel_holo_light.png b/res/drawable-xhdpi/ic_cancel_holo_light.png
new file mode 100644
index 0000000..630f3fd
--- /dev/null
+++ b/res/drawable-xhdpi/ic_cancel_holo_light.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_arrow.png b/res/drawable-xxhdpi/ic_arrow.png
new file mode 100644
index 0000000..f8e7731
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_arrow.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_cancel_holo_light.png b/res/drawable-xxhdpi/ic_cancel_holo_light.png
new file mode 100644
index 0000000..c2f5b5e
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_cancel_holo_light.png
Binary files differ
diff --git a/res/layout/tile_interactions_teaser_view.xml b/res/layout/tile_interactions_teaser_view.xml
new file mode 100644
index 0000000..ee2b974
--- /dev/null
+++ b/res/layout/tile_interactions_teaser_view.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2013 Google Inc. -->
+<com.android.dialer.list.TileInteractionTeaserView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@color/actionbar_background_color"
+    android:paddingBottom="@dimen/favorites_row_bottom_padding"
+    android:paddingTop="@dimen/favorites_row_top_padding">
+
+    <LinearLayout
+        android:id="@+id/swipeable_content"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="horizontal" >
+
+        <ImageView
+            android:id="@+id/arrow"
+            android:layout_width="48dp"
+            android:layout_height="match_parent"
+            android:layout_marginBottom="12dp"
+            android:layout_marginLeft="16dp"
+            android:layout_marginRight="12dp"
+            android:duplicateParentState="true"
+            android:src="@drawable/ic_arrow"
+            android:visibility="invisible" />
+
+        <TextView
+            android:id="@+id/text"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:layout_marginBottom="12dp"
+            android:layout_marginTop="12dp"
+            android:layout_weight="1"
+            android:duplicateParentState="true"
+            android:fontFamily="sans-serif-light"
+            android:text="@string/contact_tooltip"
+            android:textColor="@color/undo_dialogue_text_color"
+            android:textSize="16sp" />
+
+        <View
+            android:id="@+id/dismiss_separator"
+            android:layout_width="1dip"
+            android:layout_height="match_parent"
+            android:background="@color/undo_dialogue_text_color"
+            android:layout_marginTop="16dp"
+            android:layout_marginBottom="16dp"
+            android:layout_marginLeft="16dp"/>
+
+        <ImageButton
+            android:id="@+id/dismiss_button"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:background="?android:attr/selectableItemBackground"
+            android:clickable="true"
+            android:scaleType="center"
+            android:src="@drawable/ic_cancel_holo_light"
+            style="@style/DismissButtonStyle" />
+
+    </LinearLayout>
+
+</com.android.dialer.list.TileInteractionTeaserView>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index d1052d5..30adc43 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -73,4 +73,8 @@
     <dimen name="favorites_row_end_padding">8dp</dimen>
     <dimen name="favorites_row_undo_text_side_padding">32dp</dimen>
     <dimen name="recent_call_log_item_padding">8dp</dimen>
+
+    <!-- Padding for the tooltip -->
+    <dimen name="dismiss_button_padding_start">20dip</dimen>
+    <dimen name="dismiss_button_padding_end">28dip</dimen>
 </resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 791adf6..4e91897 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -145,4 +145,9 @@
         <item name="android:background">@null</item>
         <item name="android:textColorHint">@color/searchbox_text_color</item>
     </style>
+
+    <style name="DismissButtonStyle">
+        <item name="android:paddingLeft">@dimen/dismiss_button_padding_start</item>
+        <item name="android:paddingRight">@dimen/dismiss_button_padding_end</item>
+    </style>
 </resources>
diff --git a/src/com/android/dialer/list/PhoneFavoriteFragment.java b/src/com/android/dialer/list/PhoneFavoriteFragment.java
index 7e8ff0f..73703a0 100644
--- a/src/com/android/dialer/list/PhoneFavoriteFragment.java
+++ b/src/com/android/dialer/list/PhoneFavoriteFragment.java
@@ -199,6 +199,8 @@
     private View mShowAllContactsInEmptyViewButton;
     private View mContactTileFrame;
 
+    private TileInteractionTeaserView mTileInteractionTeaserView;
+
     private final HashMap<Long, Integer> mItemIdTopMap = new HashMap<Long, Integer>();
     private final HashMap<Long, Integer> mItemIdLeftMap = new HashMap<Long, Integer>();
 
@@ -306,8 +308,13 @@
 
         mContactTileFrame = mParentView.findViewById(R.id.contact_tile_frame);
 
+        mTileInteractionTeaserView = (TileInteractionTeaserView) inflater.inflate(
+                R.layout.tile_interactions_teaser_view, mListView, false);
+
         mAdapter = new PhoneFavoriteMergedAdapter(getActivity(), this, mContactTileAdapter,
-                mCallLogAdapter, mShowAllContactsButton);
+                mCallLogAdapter, mShowAllContactsButton, mTileInteractionTeaserView);
+
+        mTileInteractionTeaserView.setAdapter(mAdapter);
 
         mListView.setAdapter(mAdapter);
 
diff --git a/src/com/android/dialer/list/PhoneFavoriteMergedAdapter.java b/src/com/android/dialer/list/PhoneFavoriteMergedAdapter.java
index 1f577c1..daba39e 100644
--- a/src/com/android/dialer/list/PhoneFavoriteMergedAdapter.java
+++ b/src/com/android/dialer/list/PhoneFavoriteMergedAdapter.java
@@ -49,11 +49,14 @@
 
     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_ID = -2;
     private static final int ALL_CONTACTS_BUTTON_ITEM_ID = -1;
     private final PhoneFavoritesTileAdapter mContactTileAdapter;
     private final CallLogAdapter mCallLogAdapter;
     private final View mShowAllContactsButton;
     private final PhoneFavoriteFragment mFragment;
+    private final TileInteractionTeaserView mTileInteractionTeaserView;
 
     private final int mCallLogPadding;
 
@@ -100,7 +103,8 @@
             PhoneFavoriteFragment fragment,
             PhoneFavoritesTileAdapter contactTileAdapter,
             CallLogAdapter callLogAdapter,
-            View showAllContactsButton) {
+            View showAllContactsButton,
+            TileInteractionTeaserView tileInteractionTeaserView) {
         final Resources resources = context.getResources();
         mContext = context;
         mFragment = fragment;
@@ -111,6 +115,7 @@
         mCallLogAdapter.registerDataSetObserver(mObserver);
         mContactTileAdapter.registerDataSetObserver(mObserver);
         mShowAllContactsButton = showAllContactsButton;
+        mTileInteractionTeaserView = tileInteractionTeaserView;
         mCallLogQueryHandler = new CallLogQueryHandler(mContext.getContentResolver(),
                 mCallLogQueryHandlerListener);
     }
@@ -118,7 +123,8 @@
     @Override
     public int getCount() {
         if (mContactTileAdapter.getCount() > 0) {
-            return mContactTileAdapter.getCount() + mCallLogAdapter.getCount() + 1;
+            return mContactTileAdapter.getCount() + mCallLogAdapter.getCount() + 1 +
+                    getTeaserViewCount();
         } else {
             return mCallLogAdapter.getCount();
         }
@@ -132,9 +138,10 @@
             if (position < callLogAdapterCount) {
                 return mCallLogAdapter.getItem(position);
             }
-            // Set position to the position of the actual favorite contact in the favorites adapter
-            position = getAdjustedFavoritePosition(position, callLogAdapterCount);
         }
+        // Set position to the position of the actual favorite contact in the favorites adapter
+        position = getAdjustedFavoritePosition(position, callLogAdapterCount);
+
         return mContactTileAdapter.getItem(position);
     }
 
@@ -144,7 +151,8 @@
      *
      * These are the ranges of IDs reserved for each item type.
      *
-     * -(N + 1) to -2: CallLogAdapterItems, where N is equal to the number of call log items
+     * -(N + 1) to -3: CallLogAdapterItems, where N is equal to the number of call log items
+     * -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,
@@ -155,9 +163,14 @@
         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 - 1 - position;
-        } else if (position < (callLogAdapterCount + mContactTileAdapter.getCount())) {
-            return mContactTileAdapter.getItemId(position - callLogAdapterCount);
+            return ALL_CONTACTS_BUTTON_ITEM_ID - 2 - position;
+        } else if (position == TILE_INTERACTION_TEASER_VIEW_POSITION + callLogAdapterCount &&
+                mTileInteractionTeaserView.getShouldDisplayInList()){
+            return TILE_INTERACTION_TEASER_VIEW_ID;
+        } else if (position < (callLogAdapterCount + mContactTileAdapter.getCount() +
+                getTeaserViewCount())) {
+            return mContactTileAdapter.getItemId(
+                    getAdjustedFavoritePosition(position, callLogAdapterCount));
         } else {
             // All contacts button
             return ALL_CONTACTS_BUTTON_ITEM_ID;
@@ -171,7 +184,10 @@
 
     @Override
     public int getViewTypeCount() {
-        return (mContactTileAdapter.getViewTypeCount() + mCallLogAdapter.getViewTypeCount() + 1);
+        return (mContactTileAdapter.getViewTypeCount() +            /* Favorite and frequent */
+                mCallLogAdapter.getViewTypeCount() +                /* Recent call log */
+                getTeaserViewCount() +                              /* Teaser */
+                1);                                                 /* Show all contacts button. */
     }
 
     @Override
@@ -182,6 +198,10 @@
             // View type of the call log adapter is the last view type of the contact tile adapter
             // + 1
             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
+            return mContactTileAdapter.getViewTypeCount() + 2;
         } else if (position < getCount() - 1) {
             return mContactTileAdapter.getItemViewType(
                     getAdjustedFavoritePosition(position, callLogAdapterCount));
@@ -200,6 +220,12 @@
             return mShowAllContactsButton;
         }
 
+        if (mTileInteractionTeaserView.getShouldDisplayInList())  {
+            if (position == TILE_INTERACTION_TEASER_VIEW_POSITION + callLogAdapterCount) {
+                return mTileInteractionTeaserView;
+            }
+        }
+
         if (callLogAdapterCount > 0) {
             if (position == 0) {
                 final SwipeableCallLogRow wrapper;
@@ -224,11 +250,12 @@
                 wrapper.addView(view);
                 return wrapper;
             }
-            // Set position to the position of the actual favorite contact in the
-            // favorites adapter
-            position = getAdjustedFavoritePosition(position, callLogAdapterCount);
         }
 
+        // Set position to the position of the actual favorite contact in the
+        // favorites adapter
+        position = getAdjustedFavoritePosition(position, callLogAdapterCount);
+
         // Favorites section
         final View view = mContactTileAdapter.getView(position, convertView, parent);
         if (position >= mContactTileAdapter.getMaxTiledRows()) {
@@ -259,7 +286,17 @@
     }
 
     private int getAdjustedFavoritePosition(int position, int callLogAdapterCount) {
-        return position - callLogAdapterCount;
+        if (position - callLogAdapterCount > TILE_INTERACTION_TEASER_VIEW_POSITION &&
+                mTileInteractionTeaserView.getShouldDisplayInList()) {
+            return position - callLogAdapterCount - 1;
+        } else {
+            return position - callLogAdapterCount;
+        }
+    }
+
+    private int getTeaserViewCount() {
+        return (mContactTileAdapter.getCount() > TILE_INTERACTION_TEASER_VIEW_POSITION &&
+                mTileInteractionTeaserView.getShouldDisplayInList() ? 1 : 0);
     }
 
     /**
diff --git a/src/com/android/dialer/list/PhoneFavoritesTileAdapter.java b/src/com/android/dialer/list/PhoneFavoritesTileAdapter.java
index a4a2cb4..e28fd73 100644
--- a/src/com/android/dialer/list/PhoneFavoritesTileAdapter.java
+++ b/src/com/android/dialer/list/PhoneFavoritesTileAdapter.java
@@ -505,7 +505,11 @@
 
         int itemViewType = getItemViewType(position);
 
-        ContactTileRow contactTileRowView  = (ContactTileRow) convertView;
+        ContactTileRow contactTileRowView = null;
+
+        if (convertView instanceof  ContactTileRow) {
+            contactTileRowView  = (ContactTileRow) convertView;
+        }
 
         ArrayList<ContactEntry> contactList = getItem(position);
 
diff --git a/src/com/android/dialer/list/TileInteractionTeaserView.java b/src/com/android/dialer/list/TileInteractionTeaserView.java
new file mode 100644
index 0000000..6e70fd1
--- /dev/null
+++ b/src/com/android/dialer/list/TileInteractionTeaserView.java
@@ -0,0 +1,153 @@
+package com.android.dialer.list;
+
+import android.animation.Animator;
+
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.view.animation.DecelerateInterpolator;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.dialer.DialtactsActivity;
+import com.android.dialer.R;
+
+/**
+ * A teaser to introduce people to the contact photo check boxes
+ */
+public class TileInteractionTeaserView extends FrameLayout {
+    private static int sShrinkAnimationDuration;
+
+    private static final String KEY_TILE_INTERACTION_TEASER_SHOWN =
+            "key_tile_interaction_teaser_shown";
+
+    private boolean mNeedLayout;
+    private int mTextTop;
+    private int mAnimatedHeight = -1;
+
+    private PhoneFavoriteMergedAdapter mAdapter;
+
+    public TileInteractionTeaserView(final Context context) {
+        this(context, null);
+    }
+
+    public TileInteractionTeaserView(final Context context, final AttributeSet attrs) {
+        super(context, attrs);
+        final Resources resources = context.getResources();
+
+        mNeedLayout = true;
+        sShrinkAnimationDuration = resources.getInteger(R.integer.escape_animation_duration);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        findViewById(R.id.dismiss_button).setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                startDestroyAnimation();
+            }
+        });
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+
+        final TextView text = (TextView) findViewById(R.id.text);
+        final ImageView arrow = (ImageView) findViewById(R.id.arrow);
+
+        // We post to avoid calling layout within layout
+        arrow.post(new Runnable() {
+            @Override
+            public void run() {
+
+                // The text top is changed when we move the arrow, so we need to
+                // do multiple passes
+                int textTop = text.getTop();
+                if (mNeedLayout || textTop != mTextTop) {
+                    mNeedLayout = false;
+                    mTextTop = textTop;
+
+                    final int lineHeight = text.getLineHeight();
+                    final LinearLayout.LayoutParams arrowParams = (LinearLayout.LayoutParams) arrow
+                            .getLayoutParams();
+                    arrowParams.topMargin = mTextTop + lineHeight / 2;
+                    arrow.setLayoutParams(arrowParams);
+                }
+                arrow.setVisibility(View.VISIBLE);
+            }
+        });
+    }
+
+    public boolean getShouldDisplayInList() {
+        final SharedPreferences prefs = getContext().getSharedPreferences(
+                DialtactsActivity.SHARED_PREFS_NAME, Context.MODE_PRIVATE);
+        return prefs.getBoolean(KEY_TILE_INTERACTION_TEASER_SHOWN, true);
+    }
+
+    public void setAdapter(PhoneFavoriteMergedAdapter adapter) {
+        mAdapter = adapter;
+    }
+
+    private void startDestroyAnimation() {
+        final int start = getHeight();
+        final int end = 0;
+        mAnimatedHeight = start;
+        Log.v("Interaction", "Start from" + start);
+
+        ValueAnimator heightAnimator = ValueAnimator.ofInt(start, end);
+        heightAnimator.setDuration(sShrinkAnimationDuration);
+        heightAnimator.setInterpolator(new DecelerateInterpolator(2.0f));
+        heightAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            public void onAnimationUpdate(ValueAnimator animation) {
+                mAnimatedHeight = (Integer) animation.getAnimatedValue();
+                requestLayout();
+            }
+        });
+        heightAnimator.addListener(new Animator.AnimatorListener() {
+            @Override
+            public void onAnimationStart(Animator animator) {
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animator) {
+                setVisibility(GONE);
+                setDismissed();
+                if (mAdapter != null) {
+                    mAdapter.notifyDataSetChanged();
+                }
+            }
+
+            @Override
+            public void onAnimationCancel(Animator animator) {
+            }
+
+            @Override
+            public void onAnimationRepeat(Animator animator) {
+            }
+        });
+
+        heightAnimator.start();
+    }
+
+    private void setDismissed() {
+        final SharedPreferences prefs = getContext().getSharedPreferences(
+                DialtactsActivity.SHARED_PREFS_NAME, Context.MODE_PRIVATE);
+        prefs.edit().putBoolean(KEY_TILE_INTERACTION_TEASER_SHOWN, false).apply();
+    }
+
+    @Override
+    protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
+        if (mAnimatedHeight == -1) {
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        } else {
+            setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), mAnimatedHeight);
+        }
+    }
+}