Merge "Pause playback when voicemail is deleted." into mnc-dev
diff --git a/res/layout/call_log_fragment.xml b/res/layout/call_log_fragment.xml
index 68e3060..3a7013d 100644
--- a/res/layout/call_log_fragment.xml
+++ b/res/layout/call_log_fragment.xml
@@ -27,11 +27,10 @@
         android:paddingStart="@dimen/call_log_horizontal_margin"
         android:paddingEnd="@dimen/call_log_horizontal_margin" />
 
-    <include
+    <com.android.dialer.widget.EmptyContentView
         android:id="@+id/empty_list_view"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        layout="@layout/empty_list_view"
         android:visibility="gone" />
 
 </FrameLayout>
diff --git a/res/layout/empty_list_view.xml b/res/layout/empty_content_view.xml
similarity index 63%
rename from res/layout/empty_list_view.xml
rename to res/layout/empty_content_view.xml
index 7f961a3..18633d0 100644
--- a/res/layout/empty_list_view.xml
+++ b/res/layout/empty_content_view.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
+<!-- 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.
@@ -13,15 +13,8 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:orientation="vertical"
-    android:paddingTop="@dimen/empty_list_message_top_padding"
-    android:paddingBottom="@dimen/actionbar_and_tab_height"
-    android:minHeight="?android:attr/listPreferredItemHeight">
 
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
     <ImageView
         android:id="@+id/emptyListViewImage"
         android:layout_height="wrap_content"
@@ -39,4 +32,19 @@
         android:paddingRight="16dp"
         android:paddingLeft="16dp" />
 
-</LinearLayout>
+    <TextView
+        android:id="@+id/emptyListViewAction"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:gravity="center_horizontal"
+        android:layout_gravity="center_horizontal"
+        android:paddingRight="16dp"
+        android:paddingLeft="16dp"
+        android:paddingTop="8dp"
+        android:paddingBottom="8dp"
+        android:text="@string/permission_single_turn_on"
+        android:background="?android:attr/selectableItemBackground"
+        android:clickable="true"
+        style="@style/TextActionStyle" />
+
+</merge>
diff --git a/res/layout/show_all_contacts_fragment.xml b/res/layout/show_all_contacts_fragment.xml
index 00358dc..3b501fb 100644
--- a/res/layout/show_all_contacts_fragment.xml
+++ b/res/layout/show_all_contacts_fragment.xml
@@ -44,11 +44,10 @@
             android:nestedScrollingEnabled="true" />
     </FrameLayout>
 
-    <include
+    <com.android.dialer.widget.EmptyContentView
         android:id="@+id/empty_list_view"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        layout="@layout/empty_list_view"
         android:visibility="gone"/>
 
 </LinearLayout>
diff --git a/res/layout/speed_dial_fragment.xml b/res/layout/speed_dial_fragment.xml
index 1882049..55dd158 100644
--- a/res/layout/speed_dial_fragment.xml
+++ b/res/layout/speed_dial_fragment.xml
@@ -41,11 +41,10 @@
             android:nestedScrollingEnabled="true" />
     </FrameLayout>
 
-    <include
+    <com.android.dialer.widget.EmptyContentView
         android:id="@+id/empty_list_view"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        layout="@layout/empty_list_view"
         android:visibility="gone"/>
 
 </FrameLayout>
diff --git a/res/values-gu-rIN/strings.xml b/res/values-gu-rIN/strings.xml
index a8f4b18..064fbae 100644
--- a/res/values-gu-rIN/strings.xml
+++ b/res/values-gu-rIN/strings.xml
@@ -73,11 +73,11 @@
     <string name="action_menu_overflow_description" msgid="2303272250613084574">"વધુ વિકલ્પો"</string>
     <string name="action_menu_dialpad_button" msgid="1425910318049008136">"ડાયલ પેડ"</string>
     <string name="menu_copy" msgid="6108677035381940698">"કૉપિ કરો"</string>
-    <string name="menu_show_outgoing_only" msgid="1965570298133301970">"ફક્ત આઉટગોઇંગ દર્શાવો"</string>
-    <string name="menu_show_incoming_only" msgid="7534206815238877417">"ફક્ત આવનારા દર્શાવો"</string>
-    <string name="menu_show_missed_only" msgid="154473166059743996">"ફક્ત છૂટેલ દર્શાવો"</string>
-    <string name="menu_show_voicemails_only" msgid="1898421289561435703">"ફક્ત વૉઇસમેઇલ્સ દર્શાવો"</string>
-    <string name="menu_show_all_calls" msgid="7560347482073345885">"તમામ કૉલ્સ દર્શાવો"</string>
+    <string name="menu_show_outgoing_only" msgid="1965570298133301970">"ફક્ત આઉટગોઇંગ બતાવો"</string>
+    <string name="menu_show_incoming_only" msgid="7534206815238877417">"ફક્ત આવનારા બતાવો"</string>
+    <string name="menu_show_missed_only" msgid="154473166059743996">"ફક્ત છૂટેલ બતાવો"</string>
+    <string name="menu_show_voicemails_only" msgid="1898421289561435703">"ફક્ત વૉઇસમેઇલ્સ બતાવો"</string>
+    <string name="menu_show_all_calls" msgid="7560347482073345885">"તમામ કૉલ્સ બતાવો"</string>
     <string name="add_2sec_pause" msgid="9214012315201040129">"2-સંકડનો વિરામ ઉમેરો"</string>
     <string name="add_wait" msgid="3360818652790319634">"પ્રતીક્ષા ઉમેરો"</string>
     <string name="dialer_settings_label" msgid="4305043242594150479">"સેટિંગ્સ"</string>
@@ -128,7 +128,7 @@
     <string name="dialer_hint_find_contact" msgid="1012544667033887519">"નામ અથવા ફોન નંબર દાખલ કરો"</string>
     <string name="recentMissed_empty" msgid="4901789420356796156">"કોઈ કૉલ્સ નથી"</string>
     <string name="recentVoicemails_empty" msgid="8582424947259156664">"કોઈ તાજેતરના વૉઇસમેઇલ્સ નથી"</string>
-    <string name="show_favorites_only" msgid="5520072531022614595">"ફક્ત મનપસંદ દર્શાવો"</string>
+    <string name="show_favorites_only" msgid="5520072531022614595">"ફક્ત મનપસંદ બતાવો"</string>
     <string name="call_log_activity_title" msgid="4612824396355272023">"ઇતિહાસ"</string>
     <string name="call_log_all_title" msgid="3566738938889333307">"તમામ"</string>
     <string name="call_log_missed_title" msgid="4541142293870638971">"છૂટેલ"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 90cf08b..dcedb36 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -187,7 +187,7 @@
     <string name="voicemail_play_slower" msgid="4544796503902818832">"Уменьшить скорость воспроизведения."</string>
     <string name="voicemail_play_start_pause" msgid="3687447935787768983">"Начать или приостановить воспроизведение."</string>
     <string name="list_delimeter" msgid="4571593167738725100">", "</string>
-    <string name="display_options_title" msgid="7812852361055667468">"Упорядочить"</string>
+    <string name="display_options_title" msgid="7812852361055667468">"Отображение контактов"</string>
     <string name="sounds_and_vibration_title" msgid="1692290115642160845">"Звуки и вибрация"</string>
     <string name="accessibility_settings_title" msgid="6068141142874046249">"Специальные возможности"</string>
     <string name="ringtone_title" msgid="760362035635084653">"Рингтон"</string>
diff --git a/res/values-ta-rIN/strings.xml b/res/values-ta-rIN/strings.xml
index 98624f2..59803a3 100644
--- a/res/values-ta-rIN/strings.xml
+++ b/res/values-ta-rIN/strings.xml
@@ -20,7 +20,7 @@
     <string name="applicationLabel" msgid="8490255569343340580">"டயலர்"</string>
     <string name="launcherActivityLabel" msgid="1129729740601172692">"ஃபோன்"</string>
     <string name="dialerIconLabel" msgid="6500826552823403796">"ஃபோன்"</string>
-    <string name="recentCallsIconLabel" msgid="2639489159797075507">"அழைப்பு வரலாறு"</string>
+    <string name="recentCallsIconLabel" msgid="2639489159797075507">"அழைப்பு பதிவு"</string>
     <string name="recentCalls_callNumber" msgid="1756372533999226126">"<xliff:g id="NAME">%s</xliff:g> ஐ அழை"</string>
     <string name="call_detail_menu_report" msgid="587960283417977382">"தவறான எண் எனப் புகாரளி"</string>
     <string name="recentCalls_editNumberBeforeCall" msgid="7756171675833267857">"அழைப்பதற்கு முன் எண்ணைத் திருத்து"</string>
@@ -30,8 +30,8 @@
     <string name="recentCalls_trashVoicemail" msgid="7604696960787435655">"குரலஞ்சலை நீக்கு"</string>
     <string name="recentCalls_shareVoicemail" msgid="1416112847592942840">"குரலஞ்சலைப் பகிர்"</string>
     <string name="recentCalls_empty" msgid="8555115547405030734">"அழைப்புகள் இல்லை"</string>
-    <string name="clearCallLogConfirmation_title" msgid="801753155679372984">"அழைப்பு வரலாற்றை அழிக்கவா?"</string>
-    <string name="clearCallLogConfirmation" msgid="7899552396101432827">"வரலாற்றிலிருந்து எல்லா அழைப்புகளும் நீக்கப்படும்"</string>
+    <string name="clearCallLogConfirmation_title" msgid="801753155679372984">"அழைப்பு பதிவை அழிக்கவா?"</string>
+    <string name="clearCallLogConfirmation" msgid="7899552396101432827">"பதிவிலிருந்து எல்லா அழைப்புகளும் நீக்கப்படும்"</string>
     <string name="clearCallLogProgress_title" msgid="3372471156216306132">"அழைப்பு வரலாற்றை அழிக்கிறது…"</string>
     <plurals name="notification_voicemail_title" formatted="false" msgid="9088953961148324851">
       <item quantity="other"> <xliff:g id="COUNT">%1$d</xliff:g> குரலஞ்சல்கள் </item>
@@ -144,7 +144,7 @@
     <string name="search_shortcut_add_to_contact" msgid="4327842393369915751">"தொடர்பில் சேர்"</string>
     <string name="search_shortcut_send_sms_message" msgid="2569304043345025525">"SMS அனுப்பு"</string>
     <string name="search_shortcut_make_video_call" msgid="1265971685034465166">"வீடியோவில் அழை"</string>
-    <string name="show_call_history" msgid="1141502332266697170">"அழைப்பு வரலாறு முழுவதையும் காட்டு"</string>
+    <string name="show_call_history" msgid="1141502332266697170">"அழைப்பு பதிவு முழுவதையும் காட்டு"</string>
     <string name="num_missed_calls" msgid="8081736535604293886">"<xliff:g id="NUMBER">%s</xliff:g> புதிய தவறிய அழைப்புகள்"</string>
     <string name="speed_dial_empty" msgid="1931474498966072849">"விரைவு டயல் என்பது பிடித்த மற்றும் நீங்கள் அடிக்கடி அழைக்கும் எண்களை ஒரே தொடுதலின் மூலம் டயல் செய்யும் அம்சமாகும்."</string>
     <string name="all_contacts_empty" msgid="2299508125100209367">"தொடர்புகள் இல்லை"</string>
@@ -183,7 +183,7 @@
     <string name="voicemail_play_slower" msgid="4544796503902818832">"மெதுவாக இயக்கு."</string>
     <string name="voicemail_play_start_pause" msgid="3687447935787768983">"பிளேபேக்கைத் தொடங்கு அல்லது இடைநிறுத்து."</string>
     <string name="list_delimeter" msgid="4571593167738725100">", "</string>
-    <string name="display_options_title" msgid="7812852361055667468">"காட்சி விருப்பங்கள்"</string>
+    <string name="display_options_title" msgid="7812852361055667468">"காட்சி விருப்பத்தேர்வு"</string>
     <string name="sounds_and_vibration_title" msgid="1692290115642160845">"ஒலிகளும் அதிர்வும்"</string>
     <string name="accessibility_settings_title" msgid="6068141142874046249">"அணுகல் தன்மை"</string>
     <string name="ringtone_title" msgid="760362035635084653">"மொபைலின் ரிங்டோன்"</string>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index a197da2..505e491 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -20,7 +20,7 @@
 
     <!-- Application name used in Settings/Apps. Default label for activities
          that don't specify a label. -->
-    <string name="applicationLabel">Dialer</string>
+    <string name="applicationLabel">Phone</string>
 
     <!-- Title for the activity that dials the phone.  This is the name
          used in the Launcher icon. -->
@@ -70,7 +70,10 @@
     <string name="recentCalls_shareVoicemail">Share voicemail</string>
 
     <!-- Text displayed when the call log is empty. -->
-    <string name="recentCalls_empty">No calls</string>
+    <string name="recentCalls_empty">Your call log is empty</string>
+
+    <!-- Label of the button displayed when the call log is empty. Allows the user to make a call. -->
+    <string name="recentCalls_empty_action">Make a call</string>
 
     <!-- Title of the confirmation dialog for clearing the call log. [CHAR LIMIT=37]  -->
     <string name="clearCallLogConfirmation_title">Clear call history?</string>
@@ -466,10 +469,10 @@
     <string name="view_full_call_history_font_family">sans-serif</string>
 
     <!-- Text displayed when the list of missed calls is empty -->
-    <string name="recentMissed_empty">No calls</string>
+    <string name="recentMissed_empty">You have no missed calls.</string>
 
     <!-- Text displayed when the list of voicemails is empty -->
-    <string name="recentVoicemails_empty">No recent voicemails</string>
+    <string name="recentVoicemails_empty">Your voicemail inbox is empty.</string>
 
     <!--  Menu option to show favorite contacts only -->
     <string name="show_favorites_only">Show favorites only</string>
@@ -533,10 +536,16 @@
     <string name="num_missed_calls"><xliff:g id="number">%s</xliff:g> new missed calls</string>
 
     <!-- Shown when there are no speed dial favorites. -->
-    <string name="speed_dial_empty">Speed dial is one\u2011touch dialing for favorites and numbers you call often</string>
+    <string name="speed_dial_empty">No one is on your speed dial yet</string>
+
+    <!-- Shown as an action when there are no speed dial favorites -->
+    <string name="speed_dial_empty_add_favorite_action">Add a favorite</string>
 
     <!-- Shown when there are no contacts in the all contacts list. -->
-    <string name="all_contacts_empty">No contacts</string>
+    <string name="all_contacts_empty">You don\'t have any contacts yet</string>
+
+    <!-- Shown as an action when the all contacts list is empty -->
+    <string name="all_contacts_empty_add_contact_action">Add a contact</string>
 
     <!-- Shows up as a tooltip to provide a hint to the user that the profile pic in a contact
          card can be tapped to bring up a list of all numbers, or long pressed to start reordering
@@ -780,4 +789,28 @@
     <string name="play_dtmf_preference_key" translatable="false">button_play_dtmf_tone</string>
     <!-- DO NOT TRANSLATE. Internal key for DTMF tone length preference. -->
     <string name="dtmf_tone_length_preference_key" translatable="false">button_dtmf_settings</string>
+
+    <!-- The label of the button used to turn on a single permission -->
+    <string name="permission_single_turn_on">Turn on</string>
+
+    <!--  The label of the button used to turn on multiple permissions -->
+    <string name="permission_multiple_turn_on">Set permissions</string>
+
+    <!-- Shown as a prompt to turn on the contacts permission to enable speed dial -->
+    <string name="permission_no_speeddial">To enable speed dial,\n turn on the the Contacts permission.</string>
+
+    <!-- Shown as a prompt to turn on the phone permission to enable the call log -->
+    <string name="permission_no_calllog">To see your call log,\n turn on the Phone permission.</string>
+
+    <!-- Shown as a prompt to turn on the contacts permission to show all contacts -->
+    <string name="permission_no_contacts">To see your contacts,\n turn on the Contacts permission.</string>
+
+    <!-- Shown as a prompt to turn on the phone permission to show voicemails -->
+    <string name="permission_no_voicemail">To access your voicemail,\n turn on the Phone permission.</string>
+
+    <!-- Shown as a prompt to turn on contacts and location permissions to allow contact and nearby places search -->
+    <string name="permission_no_search">To search your contacts and nearby locations, turn on the Contacts and Location permissions.</string>
+
+    <!-- Shown as a prompt to turn on the phone permission to allow a call to be placed -->
+    <string name="permission_place_call">To place a call,\n turn on the Phone permission.</string>
 </resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 957fabf..e3a2f99 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -218,20 +218,24 @@
         <item name="cardBackgroundColor">@color/background_dialer_call_log_list_item</item>
     </style>
 
-    <style name="PromoCardActionStyle">
+    <style name="TextActionStyle">
         <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:textColor">@color/dialtacts_theme_color</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>
 
+    <style name="PromoCardActionStyle" parent="TextActionStyle">
+        <item name="android:textColor">@color/promo_card_text</item>
+        <item name="android:textSize">@dimen/call_log_list_item_actions_text_size</item>
+    </style>
+
     <style name="VoicemailPlaybackLayoutTextStyle">
         <item name="android:textSize">14sp</item>
     </style>
diff --git a/src/com/android/dialer/DialtactsActivity.java b/src/com/android/dialer/DialtactsActivity.java
index 31d1b94..85197a5 100644
--- a/src/com/android/dialer/DialtactsActivity.java
+++ b/src/com/android/dialer/DialtactsActivity.java
@@ -66,6 +66,7 @@
 import com.android.contacts.common.widget.FloatingActionButtonController;
 import com.android.contacts.commonbind.analytics.AnalyticsUtil;
 import com.android.dialer.calllog.CallLogActivity;
+import com.android.dialer.calllog.CallLogFragment;
 import com.android.dialer.database.DialerDatabaseHelper;
 import com.android.dialer.dialpad.DialpadFragment;
 import com.android.dialer.dialpad.SmartDialNameMatcher;
@@ -101,6 +102,7 @@
 public class DialtactsActivity extends TransactionSafeActivity implements View.OnClickListener,
         DialpadFragment.OnDialpadQueryChangedListener,
         OnListFragmentScrolledListener,
+        CallLogFragment.HostInterface,
         ListsFragment.HostInterface,
         SpeedDialFragment.HostInterface,
         SearchFragment.HostInterface,
@@ -1207,6 +1209,24 @@
         mListsFragment.getRemoveView().setDragDropController(dragController);
     }
 
+    /**
+     * Implemented to satisfy {@link SpeedDialFragment.HostInterface}
+     */
+    @Override
+    public void showAllContactsTab() {
+        if (mListsFragment != null) {
+            mListsFragment.showTab(ListsFragment.TAB_INDEX_ALL_CONTACTS);
+        }
+    }
+
+    /**
+     * Implemented to satisfy {@link CallLogFragment.HostInterface}
+     */
+    @Override
+    public void showDialpad() {
+        showDialpadFragment(true);
+    }
+
     @Override
     public void onPickPhoneNumberAction(Uri dataUri) {
         // Specify call-origin so that users will see the previous tab instead of
@@ -1322,7 +1342,6 @@
         return mActionBarHeight;
     }
 
-
     private int getFabAlignment() {
         if (!mIsLandscape && !isInSearchUi() &&
                 mListsFragment.getCurrentTabIndex() == ListsFragment.TAB_INDEX_SPEED_DIAL) {
diff --git a/src/com/android/dialer/calllog/CallLogFragment.java b/src/com/android/dialer/calllog/CallLogFragment.java
index 5d7c408..d1a9827 100644
--- a/src/com/android/dialer/calllog/CallLogFragment.java
+++ b/src/com/android/dialer/calllog/CallLogFragment.java
@@ -16,6 +16,8 @@
 
 package com.android.dialer.calllog;
 
+import static android.Manifest.permission.READ_CALL_LOG;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
@@ -26,6 +28,7 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.database.ContentObserver;
 import android.database.Cursor;
 import android.graphics.Rect;
@@ -46,6 +49,7 @@
 import android.widget.TextView;
 
 import com.android.contacts.common.GeoUtil;
+import com.android.contacts.common.util.PermissionsUtil;
 import com.android.contacts.common.util.ViewUtil;
 import com.android.dialer.R;
 import com.android.dialer.list.ListsFragment.HostInterface;
@@ -55,6 +59,8 @@
 import com.android.dialer.voicemail.VoicemailStatusHelper;
 import com.android.dialer.voicemail.VoicemailStatusHelper.StatusMessage;
 import com.android.dialer.voicemail.VoicemailStatusHelperImpl;
+import com.android.dialer.widget.EmptyContentView;
+import com.android.dialer.widget.EmptyContentView.OnEmptyViewActionButtonClickedListener;
 import com.android.dialerbind.ObjectFactory;
 
 import java.util.List;
@@ -63,8 +69,8 @@
  * Displays a list of call log entries. To filter for a particular kind of call
  * (all, missed or voicemails), specify it in the constructor.
  */
-public class CallLogFragment extends Fragment
-        implements CallLogQueryHandler.Listener, CallLogAdapter.CallFetcher {
+public class CallLogFragment extends Fragment implements CallLogQueryHandler.Listener,
+        CallLogAdapter.CallFetcher, OnEmptyViewActionButtonClickedListener {
     private static final String TAG = "CallLogFragment";
 
     /**
@@ -81,6 +87,8 @@
     // No date-based filtering.
     private static final int NO_DATE_LIMIT = 0;
 
+    private static final int READ_CALL_LOG_PERMISSION_REQUEST_CODE = 1;
+
     private RecyclerView mRecyclerView;
     private LinearLayoutManager mLayoutManager;
     private CallLogAdapter mAdapter;
@@ -91,7 +99,7 @@
     /** Whether there is at least one voicemail source installed. */
     private boolean mVoicemailSourcesAvailable = false;
 
-    private View mEmptyListView;
+    private EmptyContentView mEmptyListView;
     private KeyguardManager mKeyguardManager;
 
     private boolean mEmptyLoaderRunning;
@@ -116,6 +124,8 @@
     private final ContentObserver mVoicemailStatusObserver = new CustomContentObserver();
     private boolean mRefreshDataRequired = true;
 
+    private boolean mHasReadCallLogPermission = false;
+
     // Exactly same variable is in Fragment as a package private.
     private boolean mMenuVisible = true;
 
@@ -130,6 +140,16 @@
     // the date filter are included.  If zero, no date-based filtering occurs.
     private long mDateLimit = NO_DATE_LIMIT;
 
+    /*
+     * True if this instance of the CallLogFragment is the Recents screen shown in
+     * DialtactsActivity.
+     */
+    private boolean mIsRecentsFragment;
+
+    public interface HostInterface {
+        public void showDialpad();
+    }
+
     public CallLogFragment() {
         this(CallLogQueryHandler.CALL_TYPE_ALL, NO_LOG_LIMIT);
     }
@@ -139,9 +159,7 @@
     }
 
     public CallLogFragment(int filterType, int logLimit) {
-        super();
-        mCallTypeFilter = filterType;
-        mLogLimit = logLimit;
+        this(filterType, logLimit, NO_DATE_LIMIT);
     }
 
     /**
@@ -162,7 +180,8 @@
      * @param dateLimit limits results to calls occurring on or after the specified date.
      */
     public CallLogFragment(int filterType, int logLimit, long dateLimit) {
-        this(filterType, logLimit);
+        mCallTypeFilter = filterType;
+        mLogLimit = logLimit;
         mDateLimit = dateLimit;
     }
 
@@ -175,6 +194,8 @@
             mDateLimit = state.getLong(KEY_DATE_LIMIT, mDateLimit);
         }
 
+        mIsRecentsFragment = mLogLimit != NO_LOG_LIMIT;
+
         final Activity activity = getActivity();
         final ContentResolver resolver = activity.getContentResolver();
         String currentCountryIso = GeoUtil.getCurrentCountryIso(activity);
@@ -268,7 +289,9 @@
         mRecyclerView.setHasFixedSize(true);
         mLayoutManager = new LinearLayoutManager(getActivity());
         mRecyclerView.setLayoutManager(mLayoutManager);
-        mEmptyListView = view.findViewById(R.id.empty_list_view);
+        mEmptyListView = (EmptyContentView) view.findViewById(R.id.empty_list_view);
+        mEmptyListView.setImage(R.drawable.empty_call_log);
+        mEmptyListView.setActionClickedListener(this);
 
         String currentCountryIso = GeoUtil.getCurrentCountryIso(getActivity());
         boolean isShowingRecentsTab = mLogLimit != NO_LOG_LIMIT || mDateLimit != NO_DATE_LIMIT;
@@ -287,7 +310,6 @@
     @Override
     public void onViewCreated(View view, Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
-
         updateEmptyMessage(mCallTypeFilter);
         mAdapter.onRestoreInstanceState(savedInstanceState);
     }
@@ -305,6 +327,16 @@
     @Override
     public void onResume() {
         super.onResume();
+        final boolean hasReadCallLogPermission =
+                PermissionsUtil.hasPermission(getActivity(), READ_CALL_LOG);
+        if (!mHasReadCallLogPermission && hasReadCallLogPermission) {
+            // We didn't have the permission before, and now we do. Force a refresh of the call log.
+            // Note that this code path always happens on a fresh start, but mRefreshDataRequired
+            // is already true in that case anyway.
+            mRefreshDataRequired = true;
+            updateEmptyMessage(mCallTypeFilter);
+        }
+        mHasReadCallLogPermission = hasReadCallLogPermission;
         refreshData();
     }
 
@@ -359,6 +391,17 @@
     }
 
     private void updateEmptyMessage(int filterType) {
+        final Context context = getActivity();
+        if (context == null) {
+            return;
+        }
+
+        if (!PermissionsUtil.hasPermission(context, READ_CALL_LOG)) {
+            mEmptyListView.setDescription(R.string.permission_no_calllog);
+            mEmptyListView.setActionLabel(R.string.permission_single_turn_on);
+            return;
+        }
+
         final int messageId;
         switch (filterType) {
             case Calls.MISSED_TYPE:
@@ -374,8 +417,12 @@
                 throw new IllegalArgumentException("Unexpected filter type in CallLogFragment: "
                         + filterType);
         }
-        DialerUtils.configureEmptyListView(
-                mEmptyListView, R.drawable.empty_call_log, messageId, getResources());
+        mEmptyListView.setDescription(messageId);
+        if (mIsRecentsFragment) {
+            mEmptyListView.setActionLabel(R.string.recentCalls_empty_action);
+        } else {
+            mEmptyListView.setActionLabel(EmptyContentView.NO_LABEL);
+        }
     }
 
     CallLogAdapter getAdapter() {
@@ -437,4 +484,30 @@
             CallLogNotificationsHelper.updateVoicemailNotifications(getActivity());
         }
     }
+
+    @Override
+    public void onEmptyViewActionButtonClicked(String[] permissions) {
+        final Activity activity = getActivity();
+        if (activity == null) {
+            return;
+        }
+
+        if (!PermissionsUtil.hasPermission(activity, READ_CALL_LOG)) {
+            requestPermissions(new String[] {READ_CALL_LOG}, READ_CALL_LOG_PERMISSION_REQUEST_CODE);
+        } else if (mIsRecentsFragment) {
+            // Show dialpad if we are the recents fragment.
+            ((HostInterface) activity).showDialpad();
+        }
+    }
+
+    @Override
+    public void onRequestPermissionsResult(int requestCode, String[] permissions,
+            int[] grantResults) {
+        if (requestCode == READ_CALL_LOG_PERMISSION_REQUEST_CODE) {
+            if (grantResults.length >= 1 && PackageManager.PERMISSION_GRANTED == grantResults[0]) {
+                // Force a refresh of the data since we were missing the permission before this.
+                mRefreshDataRequired = true;
+            }
+        }
+    }
 }
diff --git a/src/com/android/dialer/list/AllContactsFragment.java b/src/com/android/dialer/list/AllContactsFragment.java
index d34250b..00b629c 100644
--- a/src/com/android/dialer/list/AllContactsFragment.java
+++ b/src/com/android/dialer/list/AllContactsFragment.java
@@ -16,7 +16,11 @@
 
 package com.android.dialer.list;
 
+import static android.Manifest.permission.READ_CONTACTS;
+
+import android.app.Activity;
 import android.content.Loader;
+import android.content.pm.PackageManager;
 import android.database.Cursor;
 import android.net.Uri;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
@@ -34,13 +38,19 @@
 import com.android.contacts.common.util.ViewUtil;
 import com.android.dialer.R;
 import com.android.dialer.util.DialerUtils;
+import com.android.dialer.util.IntentUtil;
+import com.android.dialer.widget.EmptyContentView;
+import com.android.dialer.widget.EmptyContentView.OnEmptyViewActionButtonClickedListener;
 
 /**
  * Fragments to show all contacts with phone numbers.
  */
-public class AllContactsFragment extends ContactEntryListFragment<ContactEntryListAdapter> {
+public class AllContactsFragment extends ContactEntryListFragment<ContactEntryListAdapter>
+        implements OnEmptyViewActionButtonClickedListener {
 
-    private View mEmptyListView;
+    private static final int READ_CONTACTS_PERMISSION_REQUEST_CODE = 1;
+
+    private EmptyContentView mEmptyListView;
 
     public AllContactsFragment() {
         setQuickContactEnabled(false);
@@ -55,9 +65,10 @@
     public void onViewCreated(View view, android.os.Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
 
-        mEmptyListView = view.findViewById(R.id.empty_list_view);
-        DialerUtils.configureEmptyListView(mEmptyListView, R.drawable.empty_contacts,
-                R.string.all_contacts_empty, getResources());
+        mEmptyListView = (EmptyContentView) view.findViewById(R.id.empty_list_view);
+        mEmptyListView.setImage(R.drawable.empty_contacts);
+        mEmptyListView.setDescription(R.string.all_contacts_empty);
+        mEmptyListView.setActionClickedListener(this);
         getListView().setEmptyView(mEmptyListView);
         mEmptyListView.setVisibility(View.GONE);
 
@@ -66,8 +77,14 @@
 
     @Override
     protected void startLoading() {
-        if (PermissionsUtil.hasContactsPermissions(getActivity())) {
+        if (PermissionsUtil.hasPermission(getActivity(), READ_CONTACTS)) {
             super.startLoading();
+            mEmptyListView.setDescription(R.string.all_contacts_empty);
+            mEmptyListView.setActionLabel(R.string.all_contacts_empty_add_contact_action);
+        } else {
+            mEmptyListView.setDescription(R.string.permission_no_contacts);
+            mEmptyListView.setActionLabel(R.string.permission_single_turn_on);
+            mEmptyListView.setVisibility(View.VISIBLE);
         }
     }
 
@@ -82,10 +99,6 @@
 
     @Override
     protected ContactEntryListAdapter createListAdapter() {
-        if (!PermissionsUtil.hasContactsPermissions(getActivity())) {
-            return new EmptyContactsListAdapter(getActivity());
-        }
-
         final DefaultContactListAdapter adapter = new DefaultContactListAdapter(getActivity()) {
             @Override
             protected void bindView(View itemView, int partition, Cursor cursor, int position) {
@@ -118,4 +131,31 @@
     protected void onItemClick(int position, long id) {
         // Do nothing. Implemented to satisfy ContactEntryListFragment.
     }
+
+    @Override
+    public void onEmptyViewActionButtonClicked(String[] permissions) {
+        final Activity activity = getActivity();
+        if (activity == null) {
+            return;
+        }
+
+        if (!PermissionsUtil.hasPermission(activity, READ_CONTACTS)) {
+            requestPermissions(new String[] {READ_CONTACTS}, READ_CONTACTS_PERMISSION_REQUEST_CODE);
+        } else {
+            // Add new contact
+            DialerUtils.startActivityWithErrorToast(activity, IntentUtil.getNewContactIntent(),
+                    R.string.add_contact_not_available);
+        }
+    }
+
+    @Override
+    public void onRequestPermissionsResult(int requestCode, String[] permissions,
+            int[] grantResults) {
+        if (requestCode == READ_CONTACTS_PERMISSION_REQUEST_CODE) {
+            if (grantResults.length >= 1 && PackageManager.PERMISSION_GRANTED == grantResults[0]) {
+                // Force a refresh of the data since we were missing the permission before this.
+                reloadData();
+            }
+        }
+    }
 }
diff --git a/src/com/android/dialer/list/EmptyContactsListAdapter.java b/src/com/android/dialer/list/EmptyContactsListAdapter.java
deleted file mode 100644
index 54bd477..0000000
--- a/src/com/android/dialer/list/EmptyContactsListAdapter.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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.list;
-
-import android.content.Context;
-import android.content.CursorLoader;
-
-import com.android.contacts.common.list.ContactEntryListAdapter;
-
-/**
- * Used to display an empty contact list when we don't have the permissions to read contacts.
- */
-public class EmptyContactsListAdapter extends ContactEntryListAdapter {
-
-    public EmptyContactsListAdapter(Context context) {
-        super(context);
-    }
-
-    @Override
-    public String getContactDisplayName(int position) {
-        return null;
-    }
-
-    @Override
-    public void configureLoader(CursorLoader loader, long directoryId) {
-        loader.setUri(null);
-    }
-
-    @Override
-    public int getCount() {
-        return 0;
-    }
-}
diff --git a/src/com/android/dialer/list/SpeedDialFragment.java b/src/com/android/dialer/list/SpeedDialFragment.java
index bf95758..aead1c8 100644
--- a/src/com/android/dialer/list/SpeedDialFragment.java
+++ b/src/com/android/dialer/list/SpeedDialFragment.java
@@ -15,6 +15,8 @@
  */
 package com.android.dialer.list;
 
+import static android.Manifest.permission.READ_CONTACTS;
+
 import android.animation.Animator;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
@@ -50,6 +52,7 @@
 import com.android.contacts.common.util.PermissionsUtil;
 import com.android.dialer.R;
 import com.android.dialer.util.DialerUtils;
+import com.android.dialer.widget.EmptyContentView;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -58,7 +61,8 @@
  * This fragment displays the user's favorite/frequent contacts in a grid.
  */
 public class SpeedDialFragment extends Fragment implements OnItemClickListener,
-        PhoneFavoritesTileAdapter.OnDataSetChangedForAnimationListener {
+        PhoneFavoritesTileAdapter.OnDataSetChangedForAnimationListener,
+        EmptyContentView.OnEmptyViewActionButtonClickedListener {
 
     /**
      * By default, the animation code assumes that all items in a list view are of the same height
@@ -81,6 +85,7 @@
 
     public interface HostInterface {
         public void setDragDropController(DragDropController controller);
+        public void showAllContactsTab();
     }
 
     private class ContactTileLoaderListener implements LoaderManager.LoaderCallbacks<Cursor> {
@@ -157,7 +162,7 @@
     /**
      * Layout used when there are no favorites.
      */
-    private View mEmptyView;
+    private EmptyContentView mEmptyView;
 
     private final ContactTileView.Listener mContactTileAdapterListener =
             new ContactTileAdapterListener();
@@ -197,9 +202,16 @@
             if (getLoaderManager().getLoader(LOADER_ID_CONTACT_TILE) == null) {
                 getLoaderManager().initLoader(LOADER_ID_CONTACT_TILE, null,
                         mContactTileLoaderListener);
+
             } else {
                 getLoaderManager().getLoader(LOADER_ID_CONTACT_TILE).forceLoad();
             }
+
+            mEmptyView.setDescription(R.string.speed_dial_empty);
+            mEmptyView.setActionLabel(R.string.speed_dial_empty_add_favorite_action);
+        } else {
+            mEmptyView.setDescription(R.string.permission_no_speeddial);
+            mEmptyView.setActionLabel(R.string.permission_single_turn_on);
         }
         Trace.endSection();
     }
@@ -221,9 +233,9 @@
                 (ImageView) getActivity().findViewById(R.id.contact_tile_drag_shadow_overlay);
         mListView.setDragShadowOverlay(dragShadowOverlay);
 
-        mEmptyView = mParentView.findViewById(R.id.empty_list_view);
-        DialerUtils.configureEmptyListView(
-                mEmptyView, R.drawable.empty_speed_dial, R.string.speed_dial_empty, getResources());
+        mEmptyView = (EmptyContentView) mParentView.findViewById(R.id.empty_list_view);
+        mEmptyView.setImage(R.drawable.empty_speed_dial);
+        mEmptyView.setActionClickedListener(this);
 
         mContactTileFrame = mParentView.findViewById(R.id.contact_tile_frame);
 
@@ -449,4 +461,19 @@
     public AbsListView getListView() {
         return mListView;
     }
+
+    @Override
+    public void onEmptyViewActionButtonClicked(String[] permissions) {
+        final Activity activity = getActivity();
+        if (activity == null) {
+            return;
+        }
+
+        if (!PermissionsUtil.hasPermission(activity, READ_CONTACTS)) {
+            requestPermissions(new String[] {READ_CONTACTS}, 0);
+        } else {
+            // Switch tabs
+            ((HostInterface) activity).showAllContactsTab();
+        }
+    }
 }
diff --git a/src/com/android/dialer/util/DialerUtils.java b/src/com/android/dialer/util/DialerUtils.java
index a44c2ee..e25ada5 100644
--- a/src/com/android/dialer/util/DialerUtils.java
+++ b/src/com/android/dialer/util/DialerUtils.java
@@ -40,6 +40,7 @@
 import com.android.contacts.common.ContactsUtils;
 import com.android.contacts.common.interactions.TouchPointManager;
 import com.android.dialer.R;
+import com.android.dialer.widget.EmptyContentView;
 import com.android.incallui.CallCardFragment;
 import com.android.incallui.Log;
 
@@ -116,27 +117,6 @@
     }
 
     /**
-     * Sets the image asset and text for an empty list view (see empty_list_view.xml).
-     *
-     * @param emptyListView The empty list view.
-     * @param imageResId The resource id for the drawable to set as the image.
-     * @param strResId The resource id for the string to set as the message.
-     * @param res The resources to obtain the image and string from.
-     */
-    public static void configureEmptyListView(
-            View emptyListView, int imageResId, int strResId, Resources res) {
-        ImageView emptyListViewImage =
-                (ImageView) emptyListView.findViewById(R.id.emptyListViewImage);
-
-        emptyListViewImage.setImageDrawable(res.getDrawable(imageResId));
-        emptyListViewImage.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
-
-        TextView emptyListViewMessage =
-                (TextView) emptyListView.findViewById(R.id.emptyListViewMessage);
-        emptyListViewMessage.setText(res.getString(strResId));
-    }
-
-    /**
      * Closes an {@link AutoCloseable}, silently ignoring any checked exceptions. Does nothing if
      * null.
      *
diff --git a/src/com/android/dialer/widget/EmptyContentView.java b/src/com/android/dialer/widget/EmptyContentView.java
new file mode 100644
index 0000000..67c9ce1
--- /dev/null
+++ b/src/com/android/dialer/widget/EmptyContentView.java
@@ -0,0 +1,102 @@
+/*
+ * 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.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.dialer.R;
+
+public class EmptyContentView extends LinearLayout implements View.OnClickListener {
+
+    public static final int NO_LABEL = 0;
+
+    private ImageView mImageView;
+    private TextView mDescriptionView;
+    private TextView mActionView;
+    private String[] mPermissions = new String[] {};
+    private OnEmptyViewActionButtonClickedListener mOnActionButtonClickedListener;
+
+    public interface OnEmptyViewActionButtonClickedListener {
+        public void onEmptyViewActionButtonClicked(String[] permissions);
+    }
+
+    public EmptyContentView(Context context) {
+        this(context, null);
+    }
+
+    public EmptyContentView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public EmptyContentView(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public EmptyContentView(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        setOrientation(LinearLayout.VERTICAL);
+
+        final LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
+                Context.LAYOUT_INFLATER_SERVICE);
+        inflater.inflate(R.layout.empty_content_view, this);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mImageView = (ImageView) findViewById(R.id.emptyListViewImage);
+        mDescriptionView = (TextView) findViewById(R.id.emptyListViewMessage);
+        mActionView = (TextView) findViewById(R.id.emptyListViewAction);
+        mActionView.setOnClickListener(this);
+    }
+
+    public void setDescription(int resourceId) {
+        mDescriptionView.setText(resourceId);
+    }
+
+    public void setImage(int resourceId) {
+        mImageView.setImageResource(resourceId);
+    }
+
+    public void setActionLabel(int resourceId) {
+        if (resourceId == NO_LABEL) {
+            mActionView.setText(null);
+            mActionView.setVisibility(View.GONE);
+        } else {
+            mActionView.setText(resourceId);
+            mActionView.setVisibility(View.VISIBLE);
+        }
+    }
+
+    public void setActionClickedListener(OnEmptyViewActionButtonClickedListener listener) {
+        mOnActionButtonClickedListener = listener;
+    }
+
+    @Override
+    public void onClick(View v) {
+        if (mOnActionButtonClickedListener != null) {
+            mOnActionButtonClickedListener.onEmptyViewActionButtonClicked(mPermissions);
+        }
+    }
+}