Add import fragment, rearrange fragments.

+ Add a fragment (and adapter) for displaying numbers from contacts
marked as send to voicemail. This fragment has import functionality.

+ Refactor logic around the Blocked Numbers activity; relocate a lot
of the fragment-specific logic, particularly around actionbars, to
within the fragments themselves.

+ Simplify fragment management logic by using replace instead of
show/hide.

Bug: 23351616
Change-Id: I5c1076d6d001a8401234f57c27ada4bcd90e6c27
diff --git a/res/layout/blocked_number_fragment.xml b/res/layout/blocked_number_fragment.xml
index f8d3030..e41d6bc 100644
--- a/res/layout/blocked_number_fragment.xml
+++ b/res/layout/blocked_number_fragment.xml
@@ -53,28 +53,36 @@
 
     </android.support.v7.widget.CardView>
 
-
-    <LinearLayout
-        android:orientation="vertical"
+    <android.support.v7.widget.CardView
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:background="@color/background_dialer_white">
+        card_view:cardCornerRadius="0dp">
 
-        <ListView android:id="@+id/blocked_numbers_list"
+        <LinearLayout
+            android:orientation="vertical"
             android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_weight="1"
-            android:drawSelectorOnTop="false"
-            android:headerDividersEnabled="false" />
+            android:layout_height="wrap_content"
+            android:background="@color/background_dialer_white">
 
-        <TextView android:id="@android:id/empty"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:paddingStart="@dimen/blocked_number_horizontal_margin"
-            android:paddingTop="@dimen/blocked_number_top_margin"
-            android:paddingBottom="@dimen/blocked_number_bottom_margin"
-            android:text="@string/listNoBlockedNumbers" />
+            <include layout="@layout/blocked_number_header" />
 
-    </LinearLayout>
+            <ListView android:id="@id/android:list"
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:layout_weight="1"
+                android:drawSelectorOnTop="false"
+                android:headerDividersEnabled="false" />
+
+            <TextView android:id="@android:id/empty"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:paddingStart="@dimen/blocked_number_horizontal_margin"
+                android:paddingTop="@dimen/blocked_number_top_margin"
+                android:paddingBottom="@dimen/blocked_number_bottom_margin"
+                android:text="@string/listNoBlockedNumbers" />
+
+        </LinearLayout>
+
+    </android.support.v7.widget.CardView>
 
 </LinearLayout>
diff --git a/res/layout/blocked_number_header.xml b/res/layout/blocked_number_header.xml
index 0c8c086..e16efbc 100644
--- a/res/layout/blocked_number_header.xml
+++ b/res/layout/blocked_number_header.xml
@@ -13,12 +13,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<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:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    card_view:cardCornerRadius="0dp">
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
 
     <TextView android:id="@+id/textView"
         android:layout_width="wrap_content"
@@ -77,4 +72,4 @@
         android:layout_marginTop="8dp"
         android:text="@string/blockNumber" />
 
-</android.support.v7.widget.CardView>
+</merge>
diff --git a/res/layout/view_numbers_to_import_fragment.xml b/res/layout/view_numbers_to_import_fragment.xml
new file mode 100644
index 0000000..fae708b
--- /dev/null
+++ b/res/layout/view_numbers_to_import_fragment.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:card_view="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:paddingTop="?android:attr/actionBarSize"
+    android:background="@color/blocked_number_background">
+
+    <ListView android:id="@id/android:list"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        android:headerDividersEnabled="false" />
+
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="bottom"
+        android:paddingTop="8dp"
+        android:paddingBottom="8dp"
+        android:background="@android:color/white">
+
+        <Button android:id="@+id/import_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentEnd="true"
+            android:layout_marginEnd="@dimen/blocked_number_container_padding"
+            android:text="@string/blocked_call_settings_import_button"
+            style="@style/DialerFlatButtonStyle" />
+
+        <Button android:id="@+id/cancel_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/import_description"
+            android:layout_toLeftOf="@id/import_button"
+            android:text="@android:string/cancel"
+            style="@style/DialerFlatButtonStyle" />
+
+    </RelativeLayout>
+
+</LinearLayout>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 333a99b..9c70dd4 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -826,6 +826,10 @@
     <!-- Label for the blocked numbers settings section [CHAR LIMIT=30] -->
     <string name="manage_blocked_numbers_label">Blocked numbers</string>
 
+    <!-- Label for fragment to import numbers from contacts marked as send to voicemail.
+         [CHAR_LIMIT=30] -->
+    <string name="import_send_to_voicemail_numbers_label">Import numbers</string>
+
     <!-- Text informing the user they have previously marked contacts to be sent to voicemail.
          This will be followed by two buttons, 1) to view who is marked to be sent to voicemail
          and 2) importing these settings to Dialer's block list. [CHAR LIMIT=NONE] -->
diff --git a/src/com/android/dialer/filterednumber/BlockedNumberAdapter.java b/src/com/android/dialer/filterednumber/BlockedNumberAdapter.java
index 93b99b4..6cd99c6 100644
--- a/src/com/android/dialer/filterednumber/BlockedNumberAdapter.java
+++ b/src/com/android/dialer/filterednumber/BlockedNumberAdapter.java
@@ -15,7 +15,6 @@
  */
 package com.android.dialer.filterednumber;
 
-import android.app.Activity;
 import android.app.FragmentManager;
 import android.database.Cursor;
 import android.content.Context;
@@ -29,7 +28,7 @@
 
 public class BlockedNumberAdapter extends NumberAdapter {
 
-    public BlockedNumberAdapter(
+    private BlockedNumberAdapter(
             Context context,
             FragmentManager fragmentManager,
             ContactInfoHelper contactInfoHelper,
diff --git a/src/com/android/dialer/filterednumber/BlockedNumberFragment.java b/src/com/android/dialer/filterednumber/BlockedNumbersFragment.java
similarity index 78%
rename from src/com/android/dialer/filterednumber/BlockedNumberFragment.java
rename to src/com/android/dialer/filterednumber/BlockedNumbersFragment.java
index 223f2ce..2f7b2f1 100644
--- a/src/com/android/dialer/filterednumber/BlockedNumberFragment.java
+++ b/src/com/android/dialer/filterednumber/BlockedNumbersFragment.java
@@ -22,13 +22,17 @@
 import android.content.Intent;
 import android.content.Loader;
 import android.database.Cursor;
+import android.graphics.drawable.ColorDrawable;
 import android.os.Bundle;
 import android.widget.CompoundButton;
-import android.widget.ListView;
 import android.widget.Switch;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.CompoundButton;
+import android.widget.Switch;
 
 import com.android.dialer.R;
 import com.android.dialer.calllog.CallLogQueryHandler;
@@ -38,7 +42,7 @@
 import com.android.dialer.voicemail.VoicemailStatusHelper;
 import com.android.dialer.voicemail.VoicemailStatusHelperImpl;
 
-public class BlockedNumberFragment extends ListFragment
+public class BlockedNumbersFragment extends ListFragment
         implements LoaderManager.LoaderCallbacks<Cursor>, View.OnClickListener,
                 CallLogQueryHandler.Listener {
 
@@ -48,7 +52,6 @@
 
     private Switch mHideSettingSwitch;
     private View mImportSettings;
-    private View mImportButton;
 
     @Override
     public void onActivityCreated(Bundle savedInstanceState) {
@@ -73,44 +76,39 @@
         });
 
         mImportSettings = getActivity().findViewById(R.id.import_settings);
-        mImportButton = getActivity().findViewById(R.id.import_button);
-        mImportButton.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                FilteredNumbersUtil.importSendToVoicemailContacts(
-                        getActivity(), new ImportSendToVoicemailContactsListener() {
-                            @Override
-                            public void onImportComplete() {
-                                mImportSettings.setVisibility(View.GONE);
-                            }
-                        });
-            }
-        });
 
+        getActivity().findViewById(R.id.import_button).setOnClickListener(this);;
+        getActivity().findViewById(R.id.view_numbers_button).setOnClickListener(this);
         getActivity().findViewById(R.id.add_number_button).setOnClickListener(this);
     }
 
     @Override
-    public void onDestroyView() {
-        super.onDestroyView();
+    public void onDestroy() {
         setListAdapter(null);
+        super.onDestroy();
     }
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-
-        LayoutInflater inflater =
-                (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-        ListView listView = (ListView) getActivity().findViewById(R.id.blocked_numbers_list);
-        listView.addHeaderView(inflater.inflate(R.layout.blocked_number_header, null));
-
         getLoaderManager().initLoader(0, null, this);
     }
 
     @Override
     public void onResume() {
         super.onResume();
+
+        ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
+        ColorDrawable backgroundDrawable =
+                new ColorDrawable(getActivity().getColor(R.color.dialer_theme_color));
+        actionBar.setBackgroundDrawable(backgroundDrawable);
+        actionBar.setElevation(getResources().getDimensionPixelSize(R.dimen.action_bar_elevation));
+        actionBar.setDisplayShowCustomEnabled(false);
+        actionBar.setDisplayHomeAsUpEnabled(true);
+        actionBar.setDisplayShowHomeEnabled(true);
+        actionBar.setDisplayShowTitleEnabled(true);
+        actionBar.setTitle(R.string.manage_blocked_numbers_label);
+
         FilteredNumbersUtil.checkForSendToVoicemailContact(
                 getActivity(), new CheckForSendToVoicemailContactListener() {
                     @Override
@@ -158,11 +156,29 @@
     }
 
     @Override
-    public void onClick(final View v) {
+    public void onClick(final View view) {
         ManageBlockedNumbersActivity manageBlockedNumbersActivity =
                 (ManageBlockedNumbersActivity) getActivity();
-        if (manageBlockedNumbersActivity != null && v.getId() == R.id.add_number_button) {
-            manageBlockedNumbersActivity.enterSearchUi();
+        if (manageBlockedNumbersActivity == null) {
+            return;
+        }
+
+        switch (view.getId()) {
+            case R.id.add_number_button:
+                manageBlockedNumbersActivity.enterSearchUi();
+                break;
+            case R.id.view_numbers_button:
+                manageBlockedNumbersActivity.showNumbersToImportPreviewUi();
+                break;
+            case R.id.import_button:
+                FilteredNumbersUtil.importSendToVoicemailContacts(manageBlockedNumbersActivity,
+                        new ImportSendToVoicemailContactsListener() {
+                            @Override
+                            public void onImportComplete() {
+                                mImportSettings.setVisibility(View.GONE);
+                            }
+                        });
+                break;
         }
     }
 
diff --git a/src/com/android/dialer/filterednumber/FilteredNumbersUtil.java b/src/com/android/dialer/filterednumber/FilteredNumbersUtil.java
index ac3d16e..8bfcea0 100644
--- a/src/com/android/dialer/filterednumber/FilteredNumbersUtil.java
+++ b/src/com/android/dialer/filterednumber/FilteredNumbersUtil.java
@@ -63,14 +63,16 @@
         static final int ID_COLUMN_INDEX = 0;
     }
 
-    private static class PhoneQuery {
+    public static class PhoneQuery {
         static final String[] PROJECTION = {
+            Contacts._ID,
             Phone.NORMALIZED_NUMBER,
             Phone.NUMBER
         };
 
-        static final int NORMALIZED_NUMBER_COLUMN_INDEX = 0;
-        static final int NUMBER_COLUMN_INDEX = 1;
+        static final int ID_COLUMN_INDEX = 0;
+        static final int NORMALIZED_NUMBER_COLUMN_INDEX = 1;
+        static final int NUMBER_COLUMN_INDEX = 2;
 
         static final String SELECT_SEND_TO_VOICEMAIL_TRUE = Contacts.SEND_TO_VOICEMAIL + "=1";
     }
diff --git a/src/com/android/dialer/filterednumber/ManageBlockedNumbersActivity.java b/src/com/android/dialer/filterednumber/ManageBlockedNumbersActivity.java
index bb194be..581ff98 100644
--- a/src/com/android/dialer/filterednumber/ManageBlockedNumbersActivity.java
+++ b/src/com/android/dialer/filterednumber/ManageBlockedNumbersActivity.java
@@ -15,20 +15,14 @@
  */
 package com.android.dialer.filterednumber;
 
-import android.app.Fragment;
-import android.app.FragmentTransaction;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
 import android.content.Intent;
-import android.graphics.drawable.ColorDrawable;
 import android.net.Uri;
 import android.os.Bundle;
-import android.support.v7.app.ActionBar;
 import android.support.v7.app.AppCompatActivity;
-import android.text.Editable;
-import android.text.TextWatcher;
 import android.util.Log;
-import android.util.TypedValue;
 import android.view.MenuItem;
-import android.widget.EditText;
 import android.widget.FrameLayout;
 import android.widget.FrameLayout.LayoutParams;
 import android.widget.Toast;
@@ -42,112 +36,36 @@
 import com.android.dialer.list.OnListFragmentScrolledListener;
 import com.android.dialer.list.BlockedListSearchFragment;
 import com.android.dialer.list.SearchFragment;
-import com.android.dialer.widget.SearchEditTextLayout;
 
 public class ManageBlockedNumbersActivity extends AppCompatActivity
         implements SearchFragment.HostInterface {
 
     private static final String TAG_BLOCKED_MANAGEMENT_FRAGMENT = "blocked_management";
     private static final String TAG_BLOCKED_SEARCH_FRAGMENT = "blocked_search";
-
-    private FilteredNumberAsyncQueryHandler mFilteredNumberAsyncQueryHandler;
-
-    private BlockedNumberFragment mManagementFragment;
-    private SearchFragment mSearchFragment;
-
-    private EditText mSearchView;
-    private ActionBar mActionBar;
-    private String mSearchQuery;
-
-    private boolean mIsShowingManagementUi;
-
-    private final TextWatcher mPhoneSearchQueryTextListener = new TextWatcher() {
-        @Override
-        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
-        }
-
-        @Override
-        public void onTextChanged(CharSequence s, int start, int before, int count) {
-            final String newText = s.toString();
-            if (newText.equals(mSearchQuery)) {
-                return;
-            }
-            mSearchQuery = newText;
-            mSearchFragment.setQueryString(mSearchQuery, false);
-        }
-
-        @Override
-        public void afterTextChanged(Editable s) {
-        }
-    };
-
-    private final SearchEditTextLayout.Callback mSearchLayoutCallback =
-            new SearchEditTextLayout.Callback() {
-                @Override
-                public void onBackButtonClicked() {
-                    showManagementUi();
-                }
-
-                @Override
-                public void onSearchViewClicked() {
-                }
-            };
+    private static final String TAG_VIEW_NUMBERS_TO_IMPORT_FRAGMENT = "view_numbers_to_import";
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.blocked_numbers_activity);
 
-        mFilteredNumberAsyncQueryHandler =
-                new FilteredNumberAsyncQueryHandler(getContentResolver());
-
         showManagementUi();
     }
 
     public void showManagementUi() {
-        mIsShowingManagementUi = true;
-
-        showManagementUiActionBar();
-
-        final FragmentTransaction transaction = getFragmentManager().beginTransaction();
-        if (mSearchFragment != null) {
-            transaction.hide(mSearchFragment);
-        }
-
-        BlockedNumberFragment fragment = (BlockedNumberFragment) getFragmentManager()
+        BlockedNumbersFragment fragment = (BlockedNumbersFragment) getFragmentManager()
                 .findFragmentByTag(TAG_BLOCKED_MANAGEMENT_FRAGMENT);
         if (fragment == null) {
-            fragment = new BlockedNumberFragment();
-            transaction.add(R.id.blocked_numbers_activity_container, fragment,
-                    TAG_BLOCKED_MANAGEMENT_FRAGMENT);
-        } else {
-            transaction.show(fragment);
+            fragment = new BlockedNumbersFragment();
         }
-        transaction.commit();
-    }
 
-    private void showManagementUiActionBar() {
-        mActionBar = getSupportActionBar();
-        ColorDrawable backgroundDrawable = new ColorDrawable(getColor(R.color.dialer_theme_color));
-        mActionBar.setBackgroundDrawable(backgroundDrawable);
-        mActionBar.setElevation(getResources().getDimensionPixelSize(R.dimen.action_bar_elevation));
-        mActionBar.setDisplayShowCustomEnabled(false);
-        mActionBar.setDisplayHomeAsUpEnabled(true);
-        mActionBar.setDisplayShowHomeEnabled(true);
-        mActionBar.setDisplayShowTitleEnabled(true);
-        mActionBar.setTitle(R.string.manage_blocked_numbers_label);
+        getFragmentManager().beginTransaction()
+                .replace(R.id.blocked_numbers_activity_container, fragment,
+                        TAG_BLOCKED_MANAGEMENT_FRAGMENT)
+                .commit();
     }
 
     public void enterSearchUi() {
-        mIsShowingManagementUi = false;
-
-        showSearchUiActionBar();
-
-        final FragmentTransaction transaction = getFragmentManager().beginTransaction();
-        if (mManagementFragment != null) {
-            transaction.hide(mManagementFragment);
-        }
-
         BlockedListSearchFragment fragment = (BlockedListSearchFragment) getFragmentManager()
                 .findFragmentByTag(TAG_BLOCKED_SEARCH_FRAGMENT);
         if (fragment == null) {
@@ -155,44 +73,27 @@
             fragment.setHasOptionsMenu(false);
             fragment.setShowEmptyListForNullQuery(true);
             fragment.setDirectorySearchEnabled(false);
-            transaction.add(R.id.blocked_numbers_activity_container, fragment,
-                    TAG_BLOCKED_SEARCH_FRAGMENT);
-        } else {
-            transaction.show(fragment);
         }
-        transaction.commit();
+
+        getFragmentManager().beginTransaction()
+                .replace(R.id.blocked_numbers_activity_container, fragment,
+                        TAG_BLOCKED_SEARCH_FRAGMENT)
+                .addToBackStack(null)
+                .commit();
     }
 
-    private void showSearchUiActionBar() {
-        mActionBar = getSupportActionBar();
-        mActionBar.setCustomView(R.layout.search_edittext);
-        mActionBar.setBackgroundDrawable(null);
-        mActionBar.setElevation(0);
-        mActionBar.setDisplayShowCustomEnabled(true);
-        mActionBar.setDisplayHomeAsUpEnabled(false);
-        mActionBar.setDisplayShowHomeEnabled(false);
-
-        final SearchEditTextLayout searchEditTextLayout = (SearchEditTextLayout) mActionBar
-                .getCustomView().findViewById(R.id.search_view_container);
-        searchEditTextLayout.expand(false, true);
-        searchEditTextLayout.setCallback(mSearchLayoutCallback);
-
-        mSearchView = (EditText) searchEditTextLayout.findViewById(R.id.search_view);
-        mSearchView.addTextChangedListener(mPhoneSearchQueryTextListener);
-        mSearchView.setHint(R.string.block_number_search_hint);
-
-        // TODO: Don't set custom text size; use default search text size.
-        mSearchView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
-                getResources().getDimension(R.dimen.blocked_number_search_text_size));
-    }
-
-    @Override
-    public void onAttachFragment(Fragment fragment) {
-        if (fragment instanceof BlockedNumberFragment) {
-            mManagementFragment = (BlockedNumberFragment) fragment;
-        } else if (fragment instanceof BlockedListSearchFragment) {
-            mSearchFragment = (BlockedListSearchFragment) fragment;
+    public void showNumbersToImportPreviewUi() {
+        ViewNumbersToImportFragment fragment = (ViewNumbersToImportFragment) getFragmentManager()
+                .findFragmentByTag(TAG_VIEW_NUMBERS_TO_IMPORT_FRAGMENT);
+        if (fragment == null) {
+            fragment = new ViewNumbersToImportFragment();
         }
+
+        getFragmentManager().beginTransaction()
+                .replace(R.id.blocked_numbers_activity_container, fragment,
+                        TAG_VIEW_NUMBERS_TO_IMPORT_FRAGMENT)
+                .addToBackStack(null)
+                .commit();
     }
 
     @Override
@@ -206,10 +107,11 @@
 
     @Override
     public void onBackPressed() {
-        if (mIsShowingManagementUi) {
-            super.onBackPressed();
+        // TODO: Achieve back navigation without overriding onBackPressed.
+        if (getFragmentManager().getBackStackEntryCount() > 0) {
+            getFragmentManager().popBackStack();
         } else {
-            showManagementUi();
+            super.onBackPressed();
         }
     }
 
diff --git a/src/com/android/dialer/filterednumber/ViewNumbersToImportAdapter.java b/src/com/android/dialer/filterednumber/ViewNumbersToImportAdapter.java
new file mode 100644
index 0000000..40b81c7
--- /dev/null
+++ b/src/com/android/dialer/filterednumber/ViewNumbersToImportAdapter.java
@@ -0,0 +1,57 @@
+/*
+ * 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.filterednumber;
+
+import android.app.FragmentManager;
+import android.database.Cursor;
+import android.content.Context;
+import android.view.View;
+
+import com.android.contacts.common.ContactPhotoManager;
+import com.android.contacts.common.GeoUtil;
+import com.android.dialer.R;
+import com.android.dialer.calllog.ContactInfoHelper;
+
+public class ViewNumbersToImportAdapter extends NumberAdapter {
+
+    private ViewNumbersToImportAdapter(
+            Context context,
+            FragmentManager fragmentManager,
+            ContactInfoHelper contactInfoHelper,
+            ContactPhotoManager contactPhotoManager) {
+        super(context, fragmentManager, contactInfoHelper, contactPhotoManager);
+    }
+
+    public static ViewNumbersToImportAdapter newViewNumbersToImportAdapter(
+            Context context, FragmentManager fragmentManager) {
+        return new ViewNumbersToImportAdapter(
+                context,
+                fragmentManager,
+                new ContactInfoHelper(context, GeoUtil.getCurrentCountryIso(context)),
+                ContactPhotoManager.getInstance(context));
+    }
+
+    @Override
+    public void bindView(View view, Context context, Cursor cursor) {
+        super.bindView(view, context, cursor);
+
+        final String number = cursor.getString(
+                FilteredNumbersUtil.PhoneQuery.NUMBER_COLUMN_INDEX);
+
+        view.findViewById(R.id.delete_button).setVisibility(View.GONE);
+        updateView(view, number, null /* countryIso */);
+    }
+}
diff --git a/src/com/android/dialer/filterednumber/ViewNumbersToImportFragment.java b/src/com/android/dialer/filterednumber/ViewNumbersToImportFragment.java
new file mode 100644
index 0000000..947dc67
--- /dev/null
+++ b/src/com/android/dialer/filterednumber/ViewNumbersToImportFragment.java
@@ -0,0 +1,127 @@
+/*
+ * 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.filterednumber;
+
+import android.app.ListFragment;
+import android.app.LoaderManager;
+import android.content.Context;
+import android.content.CursorLoader;
+import android.content.Loader;
+import android.database.Cursor;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.Contacts;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.dialer.R;
+import com.android.dialer.database.FilteredNumberContract;
+import com.android.dialer.filterednumber.FilteredNumbersUtil.ImportSendToVoicemailContactsListener;
+
+public class ViewNumbersToImportFragment extends ListFragment
+        implements LoaderManager.LoaderCallbacks<Cursor>,
+                View.OnClickListener {
+
+    private ViewNumbersToImportAdapter mAdapter;
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+
+        if (mAdapter == null) {
+            mAdapter = ViewNumbersToImportAdapter.newViewNumbersToImportAdapter(
+                    getContext(), getActivity().getFragmentManager());
+        }
+        setListAdapter(mAdapter);
+    }
+
+    @Override
+    public void onDestroy() {
+        setListAdapter(null);
+        super.onDestroy();
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getLoaderManager().initLoader(0, null, this);
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+
+        ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
+        actionBar.setTitle(R.string.import_send_to_voicemail_numbers_label);
+
+        getActivity().findViewById(R.id.cancel_button).setOnClickListener(this);
+        getActivity().findViewById(R.id.import_button).setOnClickListener(this);
+    }
+
+    @Override
+    public View onCreateView(
+            LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.view_numbers_to_import_fragment, container, false);
+    }
+
+    @Override
+    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
+        final CursorLoader cursorLoader = new CursorLoader(
+                getContext(),
+                Phone.CONTENT_URI,
+                FilteredNumbersUtil.PhoneQuery.PROJECTION,
+                FilteredNumbersUtil.PhoneQuery.SELECT_SEND_TO_VOICEMAIL_TRUE,
+                null,
+                null);
+        return cursorLoader;
+    }
+
+    @Override
+    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
+        mAdapter.swapCursor(data);
+    }
+
+    @Override
+    public void onLoaderReset(Loader<Cursor> loader) {
+        mAdapter.swapCursor(null);
+    }
+
+    @Override
+    public void onClick(final View view) {
+        switch (view.getId()) {
+            case R.id.import_button:
+                FilteredNumbersUtil.importSendToVoicemailContacts(getContext(),
+                        new ImportSendToVoicemailContactsListener() {
+                            @Override
+                            public void onImportComplete() {
+                                if (getActivity() != null) {
+                                    getActivity().onBackPressed();
+                                }
+                            }
+                        });
+                break;
+            case R.id.cancel_button:
+                getActivity().onBackPressed();
+                break;
+        }
+    }
+}
diff --git a/src/com/android/dialer/list/BlockedListSearchFragment.java b/src/com/android/dialer/list/BlockedListSearchFragment.java
index 498994f..961ce39 100644
--- a/src/com/android/dialer/list/BlockedListSearchFragment.java
+++ b/src/com/android/dialer/list/BlockedListSearchFragment.java
@@ -19,9 +19,15 @@
 import android.content.ContentValues;
 import android.net.Uri;
 import android.os.Bundle;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
+import android.text.Editable;
+import android.text.TextWatcher;
 import android.util.Log;
+import android.util.TypedValue;
 import android.view.View;
 import android.widget.AdapterView;
+import android.widget.EditText;
 import android.widget.Toast;
 
 import com.android.contacts.common.GeoUtil;
@@ -33,6 +39,7 @@
 import com.android.dialer.database.FilteredNumberAsyncQueryHandler.OnCheckBlockedListener;
 import com.android.dialer.filterednumber.FilterNumberDialogFragment;
 import com.android.dialer.filterednumber.ManageBlockedNumbersActivity;
+import com.android.dialer.widget.SearchEditTextLayout;
 
 public class BlockedListSearchFragment extends RegularSearchFragment
         implements FilterNumberDialogFragment.Callback {
@@ -40,6 +47,42 @@
 
     private FilteredNumberAsyncQueryHandler mFilteredNumberAsyncQueryHandler;
 
+    private EditText mSearchView;
+    private String mSearchQuery;
+
+    private final TextWatcher mPhoneSearchQueryTextListener = new TextWatcher() {
+        @Override
+        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+        }
+
+        @Override
+        public void onTextChanged(CharSequence s, int start, int before, int count) {
+            final String newText = s.toString();
+            if (newText.equals(mSearchQuery)) {
+                return;
+            }
+            mSearchQuery = newText;
+            setQueryString(mSearchQuery, false);
+        }
+
+        @Override
+        public void afterTextChanged(Editable s) {
+        }
+    };
+
+    private final SearchEditTextLayout.Callback mSearchLayoutCallback =
+            new SearchEditTextLayout.Callback() {
+                @Override
+                public void onBackButtonClicked() {
+                    getActivity().onBackPressed();
+                }
+
+                @Override
+                public void onSearchViewClicked() {
+                }
+            };
+
+
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -48,6 +91,32 @@
     }
 
     @Override
+    public void onResume() {
+        super.onResume();
+
+        ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
+        actionBar.setCustomView(R.layout.search_edittext);
+        actionBar.setBackgroundDrawable(null);
+        actionBar.setElevation(0);
+        actionBar.setDisplayShowCustomEnabled(true);
+        actionBar.setDisplayHomeAsUpEnabled(false);
+        actionBar.setDisplayShowHomeEnabled(false);
+
+        final SearchEditTextLayout searchEditTextLayout = (SearchEditTextLayout) actionBar
+                .getCustomView().findViewById(R.id.search_view_container);
+        searchEditTextLayout.expand(false, true);
+        searchEditTextLayout.setCallback(mSearchLayoutCallback);
+
+        mSearchView = (EditText) searchEditTextLayout.findViewById(R.id.search_view);
+        mSearchView.addTextChangedListener(mPhoneSearchQueryTextListener);
+        mSearchView.setHint(R.string.block_number_search_hint);
+
+        // TODO: Don't set custom text size; use default search text size.
+        mSearchView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
+                getResources().getDimension(R.dimen.blocked_number_search_text_size));
+    }
+
+    @Override
     protected ContactEntryListAdapter createListAdapter() {
         BlockedListSearchAdapter adapter = new BlockedListSearchAdapter(getActivity());
         adapter.setDisplayPhotos(true);