Add a promo card for visual voicemail.

The promo card explains what visual voicemail is, along with a link to
settings to disable it and an ok button to dismiss it.
Also move common resources from GoogleDialer to the respective resource
files.

Bug: 21086059
Change-Id: Iecfe778b815fb572667d0cecdb958205ec1b48a0
diff --git a/res/layout/voicemail_promo_card.xml b/res/layout/voicemail_promo_card.xml
new file mode 100644
index 0000000..103fa30
--- /dev/null
+++ b/res/layout/voicemail_promo_card.xml
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2015 Google Inc. All Rights Reserved. -->
+
+<android.support.v7.widget.CardView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:card_view="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/promo_card"
+    style="@style/CallLogCardStyle"
+    android:orientation="vertical"
+    android:gravity="center_vertical"
+    card_view:cardBackgroundColor="@color/visual_voicemail_promo_card_background">
+
+    <LinearLayout
+        android:id="@+id/promo_card_content"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingStart="@dimen/promo_card_start_padding"
+            android:paddingEnd="@dimen/promo_card_main_padding"
+            android:paddingTop="@dimen/promo_card_top_padding"
+            android:paddingBottom="@dimen/promo_card_main_padding"
+            android:orientation="horizontal"
+            android:gravity="top">
+
+            <ImageView
+                android:id="@+id/promo_card_icon"
+                android:layout_width="@dimen/promo_card_icon_size"
+                android:layout_height="@dimen/promo_card_icon_size"
+                android:layout_gravity="top"
+                android:src="@drawable/ic_voicemail_24dp"/>
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="@dimen/promo_card_main_padding"
+                android:orientation="vertical"
+                android:gravity="center_vertical">
+
+                <TextView
+                    android:id="@+id/promo_card_header"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginBottom="@dimen/promo_card_title_padding"
+                    android:layout_gravity="center_vertical"
+                    android:textColor="@color/background_dialer_white"
+                    android:textSize="@dimen/call_log_primary_text_size"
+                    android:textStyle="bold"
+                    android:text="@string/visual_voicemail_title"
+                    android:singleLine="false"/>
+
+                <TextView
+                    android:id="@+id/promo_card_details"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textColor="@color/background_dialer_white"
+                    android:textSize="@dimen/call_log_secondary_text_size"
+                    android:text="@string/visual_voicemail_text"
+                    android:lineSpacingExtra="@dimen/promo_card_line_spacing"
+                    android:singleLine="false"/>
+            </LinearLayout>
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="1dp"
+            android:background="@color/visual_voicemail_promo_card_divider"/>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingEnd="@dimen/promo_card_action_end_padding"
+            android:paddingTop="@dimen/promo_card_action_vertical_padding"
+            android:paddingBottom="@dimen/promo_card_action_vertical_padding"
+            android:orientation="horizontal"
+            android:gravity="end">
+
+            <TextView
+                android:id="@+id/settings_action"
+                style="@style/PromoCardActionStyle"
+                android:background="?android:attr/selectableItemBackground"
+                android:text="@string/visual_voicemail_settings"
+                android:nextFocusLeft="@+id/promo_card"
+                android:nextFocusRight="@+id/ok_action"
+                android:paddingEnd="@dimen/promo_card_action_between_padding"/>
+
+            <TextView
+                android:id="@+id/ok_action"
+                style="@style/PromoCardActionStyle"
+                android:background="?android:attr/selectableItemBackground"
+                android:text="@android:string/ok"
+                android:nextFocusLeft="@+id/settings_action"
+                android:nextFocusRight="@+id/promo_card"/>
+        </LinearLayout>
+    </LinearLayout>
+</android.support.v7.widget.CardView>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index f83c328..c3b0fb5 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -36,6 +36,11 @@
     <!-- Color of the text describing an unconsumed voicemail. -->
     <color name="call_log_voicemail_highlight_color">#33b5e5</color>
 
+    <!-- Background color of visual voicemail promo card. -->
+    <color name="visual_voicemail_promo_card_background">#673ab7</color>
+    <color name="visual_voicemail_promo_card_divider">#7d57c1</color>
+    <color name="promo_card_text">#ffffff</color>
+
     <!-- Tint of the recent card phone icon; 30% black -->
     <color name="call_log_list_item_primary_action_icon_tint">#4d000000</color>
 
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index bcde855..206b447 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -134,4 +134,15 @@
     <dimen name="preference_summary_line_spacing_extra">4dp</dimen>
 
     <dimen name="call_log_list_item_primary_action_dimen">36dp</dimen>
+
+    <!-- Dimensions for promo cards -->
+    <dimen name="promo_card_icon_size">24dp</dimen>
+    <dimen name="promo_card_start_padding">16dp</dimen>
+    <dimen name="promo_card_top_padding">21dp</dimen>
+    <dimen name="promo_card_main_padding">24dp</dimen>
+    <dimen name="promo_card_title_padding">12dp</dimen>
+    <dimen name="promo_card_action_vertical_padding">4dp</dimen>
+    <dimen name="promo_card_action_end_padding">4dp</dimen>
+    <dimen name="promo_card_action_between_padding">11dp</dimen>
+    <dimen name="promo_card_line_spacing">4dp</dimen>
 </resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index dab5c6a..7d5d42f 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -218,4 +218,18 @@
         <item name="cardCornerRadius">2dp</item>
         <item name="cardBackgroundColor">@color/background_dialer_call_log_list_item</item>
     </style>
+
+    <style name="PromoCardActionStyle">
+        <item name="android:layout_width">wrap_content</item>
+        <item name="android:layout_height">@dimen/call_log_action_height</item>
+        <item name="android:gravity">end|center_vertical</item>
+        <item name="android:paddingStart">@dimen/call_log_action_horizontal_padding</item>
+        <item name="android:paddingEnd">@dimen/call_log_action_horizontal_padding</item>
+        <item name="android:textColor">@color/promo_card_text</item>
+        <item name="android:textSize">@dimen/call_log_list_item_actions_text_size</item>
+        <item name="android:fontFamily">"sans-serif-medium"</item>
+        <item name="android:focusable">true</item>
+        <item name="android:singleLine">true</item>
+        <item name="android:textAllCaps">true</item>
+    </style>
 </resources>
diff --git a/src/com/android/dialer/calllog/CallLogAdapter.java b/src/com/android/dialer/calllog/CallLogAdapter.java
index 921ec50..cc3c5ba 100644
--- a/src/com/android/dialer/calllog/CallLogAdapter.java
+++ b/src/com/android/dialer/calllog/CallLogAdapter.java
@@ -18,16 +18,20 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.content.SharedPreferences;
 import android.content.res.Resources;
 import android.database.Cursor;
 import android.net.Uri;
 import android.support.v7.widget.RecyclerView;
 import android.os.Bundle;
 import android.os.Trace;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceManager;
 import android.provider.CallLog;
 import android.support.v7.widget.RecyclerView.ViewHolder;
 import android.telecom.PhoneAccountHandle;
 import android.telephony.PhoneNumberUtils;
+import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -62,6 +66,21 @@
     private static final int VIEW_TYPE_SHOW_CALL_HISTORY_LIST_ITEM = 10;
     private static final int NO_EXPANDED_LIST_ITEM = -1;
 
+    private static final int VOICEMAIL_PROMO_CARD_POSITION = 0;
+    /**
+     * View type for voicemail promo card.  Note: Numbering starts at 20 to avoid collision
+     * with {@link com.android.common.widget.GroupingListAdapter#ITEM_TYPE_IN_GROUP}, and
+     * {@link CallLogAdapter#VIEW_TYPE_SHOW_CALL_HISTORY_LIST_ITEM}.
+     */
+    private static final int VIEW_TYPE_VOICEMAIL_PROMO_CARD = 20;
+
+    /**
+     * The key for the show voicemail promo card preference which will determine whether the promo
+     * card was permanently dismissed or not.
+     */
+    private static final String SHOW_VOICEMAIL_PROMO_CARD = "show_voicemail_promo_card";
+    private static final boolean SHOW_VOICEMAIL_PROMO_CARD_DEFAULT = true;
+
     protected final Context mContext;
     private final ContactInfoHelper mContactInfoHelper;
     private final VoicemailPlaybackPresenter mVoicemailPlaybackPresenter;
@@ -97,6 +116,10 @@
 
     private boolean mLoading = true;
 
+    private SharedPreferences mPrefs;
+
+    private boolean mShowPromoCard = false;
+
     /** Instance of helper class for managing views. */
     private final CallLogListItemHelper mCallLogViewsHelper;
 
@@ -135,6 +158,30 @@
         }
     };
 
+    /**
+     * Click handler used to dismiss the promo card when the user taps the "ok" button.
+     */
+    private final View.OnClickListener mOkActionListener = new View.OnClickListener() {
+        @Override
+        public void onClick(View view) {
+            dismissVoicemailPromoCard();
+        }
+    };
+
+    /**
+     * Click handler used to send the user to the voicemail settings screen and then dismiss the
+     * promo card.
+     */
+    private final View.OnClickListener mVoicemailSettingsActionListener =
+            new View.OnClickListener() {
+        @Override
+        public void onClick(View view) {
+            Intent intent = new Intent(TelephonyManager.ACTION_CONFIGURE_VOICEMAIL);
+            mContext.startActivity(intent);
+            dismissVoicemailPromoCard();
+        }
+    };
+
     private void expandViewHolderActions(CallLogListItemViewHolder viewHolder) {
         // If another item is expanded, notify it that it has changed. Its actions will be
         // hidden when it is re-binded because we change mCurrentlyExpandedPosition below.
@@ -212,6 +259,8 @@
                 new PhoneCallDetailsHelper(mContext, resources, mPhoneNumberUtilsWrapper);
         mCallLogViewsHelper = new CallLogListItemHelper(phoneCallDetailsHelper, resources);
         mCallLogGroupBuilder = new CallLogGroupBuilder(this);
+        mPrefs = PreferenceManager.getDefaultSharedPreferences(context);
+        maybeShowVoicemailPromoCard();
     }
 
     public void onSaveInstanceState(Bundle outState) {
@@ -279,6 +328,8 @@
     public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
         if (viewType == VIEW_TYPE_SHOW_CALL_HISTORY_LIST_ITEM) {
             return ShowCallHistoryViewHolder.create(mContext, parent);
+        } else if (viewType == VIEW_TYPE_VOICEMAIL_PROMO_CARD) {
+            return createVoicemailPromoCardViewHolder(parent);
         }
         return createCallLogEntryViewHolder(parent);
     }
@@ -313,19 +364,52 @@
      * TODO: This gets called 20-30 times when Dialer starts up for a single call log entry and
      * should not. It invokes cross-process methods and the repeat execution can get costly.
      *
-     * @param callLogItemView the view corresponding to this entry
-     * @param count the number of entries in the current item, greater than 1 if it is a group
+     * @param ViewHolder The view corresponding to this entry.
+     * @param position The position of the entry.
      */
     public void onBindViewHolder(ViewHolder viewHolder, int position) {
-        if (getItemViewType(position) == VIEW_TYPE_SHOW_CALL_HISTORY_LIST_ITEM) {
-            return;
-        }
         Trace.beginSection("onBindViewHolder: " + position);
+
+        switch (getItemViewType(position)) {
+            case VIEW_TYPE_SHOW_CALL_HISTORY_LIST_ITEM:
+                break;
+            case VIEW_TYPE_VOICEMAIL_PROMO_CARD:
+                bindVoicemailPromoCardViewHolder(viewHolder);
+                break;
+            default:
+                bindCallLogListViewHolder(viewHolder, position);
+                break;
+        }
+
+        Trace.endSection();
+    }
+
+    /**
+     * Binds the promo card view holder.
+     *
+     * @param viewHolder The promo card view holder.
+     */
+    protected void bindVoicemailPromoCardViewHolder(ViewHolder viewHolder) {
+        PromoCardViewHolder promoCardViewHolder = (PromoCardViewHolder) viewHolder;
+
+        promoCardViewHolder.getSettingsTextView().setOnClickListener(
+                mVoicemailSettingsActionListener);
+        promoCardViewHolder.getOkTextView().setOnClickListener(mOkActionListener);
+    }
+
+    /**
+     * Binds the view holder for the call log list item view.
+     *
+     * @param viewHolder The call log list item view holder.
+     * @param position The position of the list item.
+     */
+
+    private void bindCallLogListViewHolder(ViewHolder viewHolder, int position) {
         Cursor c = (Cursor) getItem(position);
         if (c == null) {
-            Trace.endSection();
             return;
         }
+
         int count = getGroupSize(position);
 
         final String number = c.getString(CallLogQuery.NUMBER);
@@ -428,22 +512,35 @@
             mViewTreeObserver = views.rootView.getViewTreeObserver();
             mViewTreeObserver.addOnPreDrawListener(this);
         }
-        Trace.endSection();
     }
 
     @Override
     public int getItemCount() {
-        return super.getItemCount() + (isShowingRecentsTab() ? 1 : 0);
+        return super.getItemCount() + ((isShowingRecentsTab() || mShowPromoCard) ? 1 : 0);
     }
 
     @Override
     public int getItemViewType(int position) {
         if (position == getItemCount() - 1 && isShowingRecentsTab()) {
             return VIEW_TYPE_SHOW_CALL_HISTORY_LIST_ITEM;
+        } else if (position == VOICEMAIL_PROMO_CARD_POSITION && mShowPromoCard) {
+            return VIEW_TYPE_VOICEMAIL_PROMO_CARD;
         }
         return super.getItemViewType(position);
     }
 
+    /**
+     * Retrieves an item at the specified position, taking into account the presence of a promo
+     * card.
+     *
+     * @param position The position to retrieve.
+     * @return The item at that position.
+     */
+    @Override
+    public Object getItem(int position) {
+        return super.getItem(position - (mShowPromoCard ? 1 : 0));
+    }
+
     protected boolean isShowingRecentsTab() {
         return mIsShowingRecentsTab;
     }
@@ -597,4 +694,37 @@
            return mContext.getResources().getString(R.string.call_log_header_other);
        }
     }
+
+    /**
+     * Determines if the voicemail promo card should be shown or not.  The voicemail promo card will
+     * be shown as the first item in the voicemail tab.
+     */
+    private void maybeShowVoicemailPromoCard() {
+        boolean showPromoCard = mPrefs.getBoolean(SHOW_VOICEMAIL_PROMO_CARD,
+                SHOW_VOICEMAIL_PROMO_CARD_DEFAULT);
+        mShowPromoCard = (mVoicemailPlaybackPresenter != null) && showPromoCard;
+    }
+
+    /**
+     * Dismisses the voicemail promo card and refreshes the call log.
+     */
+    private void dismissVoicemailPromoCard() {
+        mPrefs.edit().putBoolean(SHOW_VOICEMAIL_PROMO_CARD, false).apply();
+        mShowPromoCard = false;
+        notifyItemRemoved(VOICEMAIL_PROMO_CARD_POSITION);
+    }
+
+    /**
+     * Creates the view holder for the voicemail promo card.
+     *
+     * @param parent The parent view.
+     * @return The {@link ViewHolder}.
+     */
+    protected ViewHolder createVoicemailPromoCardViewHolder(ViewGroup parent) {
+        LayoutInflater inflater = LayoutInflater.from(mContext);
+        View view = inflater.inflate(R.layout.voicemail_promo_card, parent, false);
+
+        PromoCardViewHolder viewHolder = PromoCardViewHolder.create(view);
+        return viewHolder;
+    }
 }
diff --git a/src/com/android/dialer/calllog/PromoCardViewHolder.java b/src/com/android/dialer/calllog/PromoCardViewHolder.java
new file mode 100644
index 0000000..4c96027
--- /dev/null
+++ b/src/com/android/dialer/calllog/PromoCardViewHolder.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2015 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.dialer.calllog;
+
+import com.android.dialer.R;
+
+import android.support.v7.widget.CardView;
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+
+/**
+ * View holder class for a promo card which will appear in the voicemail tab.
+ */
+public class PromoCardViewHolder extends RecyclerView.ViewHolder {
+    public static PromoCardViewHolder create(View rootView) {
+        return new PromoCardViewHolder(rootView);
+    }
+
+    /**
+     * The "Settings" button view.
+     */
+    private View mSettingsTextView;
+
+    /**
+     * The "Ok" button view.
+     */
+    private View mOkTextView;
+
+    /**
+     * Creates an instance of the {@link ViewHolder}.
+     *
+     * @param rootView The root view.
+     */
+    private PromoCardViewHolder(View rootView) {
+        super(rootView);
+
+        mSettingsTextView = rootView.findViewById(R.id.settings_action);
+        mOkTextView = rootView.findViewById(R.id.ok_action);
+    }
+
+    /**
+     * Retrieves the "Settings" button.
+     *
+     * @return The view.
+     */
+    public View getSettingsTextView() {
+        return mSettingsTextView;
+    }
+
+    /**
+     * Retrieves the "Ok" button.
+     *
+     * @return The view.
+     */
+    public View getOkTextView() {
+        return mOkTextView;
+    }
+}