Add search for adding blocked numbers to the blocked number management screen.

Bug: 24134038
Change-Id: I30b283a6b67d7e64b58138762079c4bceb8fc64f
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 1faab2a..e58d2ce 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -148,6 +148,13 @@
                   android:exported="false">
         </activity>
 
+        <activity android:name="com.android.dialer.filterednumber.BlockedNumberSearchActivity"
+            android:label="@string/dialer_settings_label"
+            android:parentActivityName="com.android.dialer.settings.DialerSettingsActivity"
+            android:theme="@style/DialtactsActivityTheme"
+            android:windowSoftInputMode="stateVisible">
+        </activity>
+
         <activity android:name="com.android.dialer.calllog.CallLogActivity"
             android:label="@string/call_log_activity_title"
             android:theme="@style/DialtactsThemeWithoutActionBarOverlay"
diff --git a/res/drawable-hdpi/ic_not_interested_googblue_24dp.png b/res/drawable-hdpi/ic_not_interested_googblue_24dp.png
new file mode 100644
index 0000000..26a26f9
--- /dev/null
+++ b/res/drawable-hdpi/ic_not_interested_googblue_24dp.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_not_interested_googblue_24dp.png b/res/drawable-mdpi/ic_not_interested_googblue_24dp.png
new file mode 100644
index 0000000..d7d5c58
--- /dev/null
+++ b/res/drawable-mdpi/ic_not_interested_googblue_24dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_not_interested_googblue_24dp.png b/res/drawable-xhdpi/ic_not_interested_googblue_24dp.png
new file mode 100644
index 0000000..3e6ec07
--- /dev/null
+++ b/res/drawable-xhdpi/ic_not_interested_googblue_24dp.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_not_interested_googblue_24dp.png b/res/drawable-xxhdpi/ic_not_interested_googblue_24dp.png
new file mode 100644
index 0000000..7c256b5
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_not_interested_googblue_24dp.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_not_interested_googblue_24dp.png b/res/drawable-xxxhdpi/ic_not_interested_googblue_24dp.png
new file mode 100644
index 0000000..6591ed4
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_not_interested_googblue_24dp.png
Binary files differ
diff --git a/res/layout/search_activity.xml b/res/layout/search_activity.xml
new file mode 100644
index 0000000..8feeac2
--- /dev/null
+++ b/res/layout/search_activity.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/search_activity_container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+</FrameLayout>
\ No newline at end of file
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index f71f128..b36066a 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -153,4 +153,5 @@
     <dimen name="blocked_number_primary_text_size">16sp</dimen>
     <dimen name="blocked_number_secondary_text_size">12sp</dimen>
     <dimen name="blocked_number_delete_icon_size">32dp</dimen>
+    <dimen name="blocked_number_search_text_size">16sp</dimen>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 093aa19..c8b238f 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -470,6 +470,10 @@
          [CHAR LIMIT=30] -->
     <string name="dialer_hint_find_contact">Search contacts</string>
 
+    <!-- Hint displayed in add blocked number search box when there is no query typed.
+         [CHAR LIMIT=30] -->
+    <string name="block_number_search_hint">Add number or search contacts</string>
+
     <!-- String resource for the font-family to use for the call log activity's title
          Do not translate. -->
     <string name="call_log_activity_title_font_family">sans-serif-light</string>
@@ -559,6 +563,9 @@
     <!-- Shortcut item used to make a video call directly from search. [CHAR LIMIT=25] -->
     <string name="search_shortcut_make_video_call">Make video call</string>
 
+    <!-- Shortcut item used to block a number directly from search. [CHAR LIMIT=25] -->
+    <string name="search_shortcut_block_number">Block number</string>
+
     <!-- Number of missed calls shown on call card [CHAR LIMIT=40] -->
     <string name="num_missed_calls"><xliff:g id="number">%s</xliff:g> new missed calls</string>
 
diff --git a/src/com/android/dialer/filterednumber/BlockedNumberFragment.java b/src/com/android/dialer/filterednumber/BlockedNumberFragment.java
index 455982a..de32fd6 100644
--- a/src/com/android/dialer/filterednumber/BlockedNumberFragment.java
+++ b/src/com/android/dialer/filterednumber/BlockedNumberFragment.java
@@ -15,26 +15,19 @@
  */
 package com.android.dialer.filterednumber;
 
-import android.app.AlertDialog;
 import android.app.ListFragment;
 import android.app.LoaderManager;
 import android.content.CursorLoader;
-import android.content.DialogInterface;
+import android.content.Intent;
 import android.content.Loader;
 import android.database.Cursor;
 import android.os.Bundle;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.Toast;
 
-import com.android.contacts.common.GeoUtil;
-import com.android.contacts.common.dialog.IndeterminateProgressDialog;
 import com.android.dialer.R;
 import com.android.dialer.database.FilteredNumberAsyncQueryHandler;
-import com.android.dialer.database.FilteredNumberAsyncQueryHandler.OnCheckBlockedListener;
 import com.android.dialer.database.FilteredNumberContract;
 
 public class BlockedNumberFragment extends ListFragment implements
@@ -105,50 +98,6 @@
 
     @Override
     public void onClick(final View v) {
-        final String countryIso = GeoUtil.getCurrentCountryIso(getContext());
-        final EditText numberField = new EditText(getContext());
-        final DialogInterface.OnClickListener okListener = new DialogInterface.OnClickListener() {
-            public void onClick(DialogInterface dialog, int whichButton) {
-                final String number = numberField.getText().toString();
-                final IndeterminateProgressDialog progressDialog =
-                        IndeterminateProgressDialog.show(getFragmentManager(),
-                                getString(R.string.checkingNumber, number), null, 1000);
-                final String normalizedNumber =
-                        FilteredNumberAsyncQueryHandler.getNormalizedNumber(number, countryIso);
-                if (normalizedNumber == null) {
-                    progressDialog.dismiss();
-                    Toast.makeText(getContext(), getString(R.string.invalidNumber, number),
-                            Toast.LENGTH_LONG).show();
-                } else {
-                    final OnCheckBlockedListener onCheckListener = new OnCheckBlockedListener() {
-                        @Override
-                        public void onCheckComplete(Integer id) {
-                            progressDialog.dismiss();
-                            if (id == null) {
-                                FilterNumberDialogFragment newFragment =
-                                        FilterNumberDialogFragment.newInstance(id, normalizedNumber,
-                                                number, countryIso, number);
-                                newFragment.setQueryHandler(mFilteredNumberAsyncQueryHandler);
-                                newFragment.setParentView(v);
-                                newFragment.show(getActivity().getFragmentManager(),
-                                        FilterNumberDialogFragment.BLOCK_DIALOG_FRAGMENT);
-                            } else {
-                                Toast.makeText(getContext(),
-                                        getString(R.string.alreadyBlocked, number),
-                                        Toast.LENGTH_LONG).show();
-                            }
-                        }
-                    };
-                    mFilteredNumberAsyncQueryHandler.startBlockedQuery(
-                            onCheckListener, normalizedNumber, number, countryIso);
-                }
-            }
-        };
-        new AlertDialog.Builder(getContext())
-                .setTitle(getString(R.string.blockNumber))
-                .setView(numberField)
-                .setPositiveButton(getString(R.string.blockNumberOk), okListener)
-                .setNegativeButton(android.R.string.cancel, null)
-                .show();
+        startActivity(new Intent(getActivity(), BlockedNumberSearchActivity.class));
     }
 }
\ No newline at end of file
diff --git a/src/com/android/dialer/filterednumber/BlockedNumberSearchActivity.java b/src/com/android/dialer/filterednumber/BlockedNumberSearchActivity.java
new file mode 100644
index 0000000..5831ddc
--- /dev/null
+++ b/src/com/android/dialer/filterednumber/BlockedNumberSearchActivity.java
@@ -0,0 +1,222 @@
+/*
+ * 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.Fragment;
+import android.app.FragmentTransaction;
+import android.content.Intent;
+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.widget.EditText;
+import android.widget.FrameLayout;
+import android.widget.FrameLayout.LayoutParams;
+import android.widget.Toast;
+
+import com.android.contacts.common.GeoUtil;
+import com.android.contacts.common.dialog.IndeterminateProgressDialog;
+import com.android.contacts.common.list.OnPhoneNumberPickerActionListener;
+import com.android.dialer.R;
+import com.android.dialer.database.FilteredNumberAsyncQueryHandler;
+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 BlockedNumberSearchActivity extends AppCompatActivity
+        implements SearchFragment.HostInterface, OnPhoneNumberPickerActionListener {
+    private static final String TAG = "BlockedNumberSearch";
+    private static final String TAG_BLOCKED_SEARCH_FRAGMENT = "blocked_search";
+
+    private FilteredNumberAsyncQueryHandler mFilteredNumberAsyncQueryHandler;
+    private SearchFragment mSearchFragment;
+    private EditText mSearchView;
+    private ActionBar mActionBar;
+    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;
+            mSearchFragment.setQueryString(mSearchQuery, false);
+        }
+
+        @Override
+        public void afterTextChanged(Editable s) {
+        }
+    };
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mFilteredNumberAsyncQueryHandler =
+                new FilteredNumberAsyncQueryHandler(getContentResolver());
+
+        setContentView(R.layout.search_activity);
+
+        mActionBar = getSupportActionBar();
+        mActionBar.setCustomView(R.layout.search_edittext);
+        mActionBar.setBackgroundDrawable(null);
+        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(new SearchEditTextLayout.Callback() {
+            @Override
+            public void onBackButtonClicked() {
+                onBackPressed();
+            }
+
+            @Override
+            public void onSearchViewClicked() {
+            }
+        });
+
+        mSearchView = (EditText) searchEditTextLayout.findViewById(R.id.search_view);
+        mSearchView.addTextChangedListener(mPhoneSearchQueryTextListener);
+        mSearchView.setHint(R.string.block_number_search_hint);
+        mSearchView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
+                getResources().getDimension(R.dimen.blocked_number_search_text_size));
+
+        enterSearchUi();
+    }
+
+    private void enterSearchUi() {
+        if (mSearchFragment != null) {
+            return;
+        }
+        final FragmentTransaction transaction = getFragmentManager().beginTransaction();
+        SearchFragment fragment = (SearchFragment) getFragmentManager()
+                .findFragmentByTag(TAG_BLOCKED_SEARCH_FRAGMENT);
+        if (fragment == null) {
+            fragment = new BlockedListSearchFragment();
+            transaction.add(R.id.search_activity_container, fragment, TAG_BLOCKED_SEARCH_FRAGMENT);
+        } else {
+            transaction.show(fragment);
+        }
+        fragment.setHasOptionsMenu(false);
+        fragment.setShowEmptyListForNullQuery(true);
+        transaction.commit();
+    }
+
+    @Override
+    public void onAttachFragment(Fragment fragment) {
+        if (fragment instanceof BlockedListSearchFragment) {
+            mSearchFragment = (BlockedListSearchFragment) fragment;
+            mSearchFragment.setOnPhoneNumberPickerActionListener(this);
+        }
+    }
+
+    @Override
+    public void onPickPhoneNumberAction(Uri dataUri, int callInitiationType) {
+        Log.w(TAG, "onPickPhoneNumberAction unsupported, ignoring.");
+    }
+
+    @Override
+    public void onCallNumberDirectly(
+            String phoneNumber, boolean isVideoCall, int callInitiationType) {
+        blockNumber(phoneNumber);
+    }
+
+    @Override
+    public void onShortcutIntentCreated(Intent intent) {
+        Log.w(TAG, "Unsupported intent has come (" + intent + "). Ignoring.");
+    }
+
+    @Override
+    public void onHomeInActionBarSelected() {
+    }
+
+    private void blockNumber(final String number) {
+        final String countryIso = GeoUtil.getCurrentCountryIso(BlockedNumberSearchActivity.this);
+        final IndeterminateProgressDialog progressDialog =
+                IndeterminateProgressDialog.show(getFragmentManager(),
+                        getString(R.string.checkingNumber, number), null, 500);
+        final String normalizedNumber =
+                FilteredNumberAsyncQueryHandler.getNormalizedNumber(number, countryIso);
+        if (normalizedNumber == null) {
+            progressDialog.dismiss();
+            Toast.makeText(
+                    BlockedNumberSearchActivity.this, getString(R.string.invalidNumber, number),
+                    Toast.LENGTH_SHORT).show();
+        } else {
+            final FilteredNumberAsyncQueryHandler.OnCheckBlockedListener onCheckListener =
+                    new FilteredNumberAsyncQueryHandler.OnCheckBlockedListener() {
+                        @Override
+                        public void onCheckComplete(Integer id) {
+                            progressDialog.dismiss();
+                            if (id == null) {
+                                final FilterNumberDialogFragment newFragment =
+                                        FilterNumberDialogFragment.newInstance(id, normalizedNumber,
+                                                number, countryIso, number);
+                                newFragment.setQueryHandler(mFilteredNumberAsyncQueryHandler);
+                                newFragment.setParentView(
+                                        findViewById(R.id.search_activity_container));
+                                newFragment.show(getFragmentManager(),
+                                        FilterNumberDialogFragment.BLOCK_DIALOG_FRAGMENT);
+                            } else {
+                                Toast.makeText(BlockedNumberSearchActivity.this,
+                                        getString(R.string.alreadyBlocked, number),
+                                        Toast.LENGTH_SHORT).show();
+                            }
+                        }
+                    };
+            mFilteredNumberAsyncQueryHandler.startBlockedQuery(
+                    onCheckListener, normalizedNumber, number, countryIso);
+        }
+    }
+
+    @Override
+    public boolean isActionBarShowing() {
+        return true;
+    }
+
+    @Override
+    public boolean isDialpadShown() {
+        return false;
+    }
+
+    @Override
+    public int getDialpadHeight() {
+        return 0;
+    }
+
+    @Override
+    public int getActionBarHideOffset() {
+        return getSupportActionBar().getHideOffset();
+    }
+
+    @Override
+    public int getActionBarHeight() {
+        return getResources().getDimensionPixelSize(R.dimen.action_bar_height_large);
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/dialer/list/BlockedListSearchAdapter.java b/src/com/android/dialer/list/BlockedListSearchAdapter.java
new file mode 100644
index 0000000..52e0c64
--- /dev/null
+++ b/src/com/android/dialer/list/BlockedListSearchAdapter.java
@@ -0,0 +1,35 @@
+/*
+ * 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;
+
+/**
+ * List adapter to display search results for adding a blocked number.
+ */
+public class BlockedListSearchAdapter extends RegularSearchListAdapter {
+
+    public BlockedListSearchAdapter(Context context) {
+        super(context);
+        disableAllShortcuts();
+        setShortcutEnabled(SHORTCUT_BLOCK_NUMBER, true);
+    }
+
+    @Override
+    protected boolean isChanged(boolean showNumberShortcuts) {
+        return setShortcutEnabled(SHORTCUT_BLOCK_NUMBER, showNumberShortcuts || mIsQuerySipAddress);
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/dialer/list/BlockedListSearchFragment.java b/src/com/android/dialer/list/BlockedListSearchFragment.java
new file mode 100644
index 0000000..bd1dd6f
--- /dev/null
+++ b/src/com/android/dialer/list/BlockedListSearchFragment.java
@@ -0,0 +1,62 @@
+/*
+ * 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.util.Log;
+
+import com.android.contacts.common.list.ContactEntryListAdapter;
+import com.android.contacts.common.list.OnPhoneNumberPickerActionListener;
+
+public class BlockedListSearchFragment extends RegularSearchFragment {
+    private static final String TAG = BlockedListSearchFragment.class.getSimpleName();
+
+    @Override
+    protected ContactEntryListAdapter createListAdapter() {
+        BlockedListSearchAdapter adapter = new BlockedListSearchAdapter(getActivity());
+        adapter.setDisplayPhotos(true);
+        adapter.setUseCallableUri(usesCallableUri());
+        return adapter;
+    }
+
+    @Override
+    protected void onItemClick(int position, long id) {
+        final DialerPhoneNumberListAdapter adapter = (DialerPhoneNumberListAdapter) getAdapter();
+        final int shortcutType = adapter.getShortcutTypeFromPosition(position);
+        final OnPhoneNumberPickerActionListener listener = getOnPhoneNumberPickerListener();
+        final String number;
+
+        if (listener == null) {
+            Log.d(TAG, "getOnPhoneNumberPickerListener() returned null in onItemClick.");
+            return;
+        }
+
+        switch (shortcutType) {
+            case DialerPhoneNumberListAdapter.SHORTCUT_INVALID:
+                // Handles click on a search result, either contact or nearby places result.
+                number = adapter.getPhoneNumber(position);
+                listener.onCallNumberDirectly(number, false, getCallInitiationType(false));
+                break;
+            case DialerPhoneNumberListAdapter.SHORTCUT_BLOCK_NUMBER:
+                // Handles click on 'Block number' shortcut to add the user query as a number.
+                number = adapter.getQueryString();
+                listener.onCallNumberDirectly(number, false, getCallInitiationType(false));
+                break;
+            default:
+                Log.w(TAG, "Ignoring unsupported shortcut type: " + shortcutType);
+                break;
+        }
+    }
+}
diff --git a/src/com/android/dialer/list/DialerPhoneNumberListAdapter.java b/src/com/android/dialer/list/DialerPhoneNumberListAdapter.java
index 401b0b6..f56c696 100644
--- a/src/com/android/dialer/list/DialerPhoneNumberListAdapter.java
+++ b/src/com/android/dialer/list/DialerPhoneNumberListAdapter.java
@@ -33,8 +33,9 @@
     public final static int SHORTCUT_ADD_TO_EXISTING_CONTACT = 2;
     public final static int SHORTCUT_SEND_SMS_MESSAGE = 3;
     public final static int SHORTCUT_MAKE_VIDEO_CALL = 4;
+    public final static int SHORTCUT_BLOCK_NUMBER = 5;
 
-    public final static int SHORTCUT_COUNT = 5;
+    public final static int SHORTCUT_COUNT = 6;
 
     private final boolean[] mShortcutEnabled = new boolean[SHORTCUT_COUNT];
 
@@ -167,6 +168,10 @@
                 text = resources.getString(R.string.search_shortcut_make_video_call);
                 drawableId = R.drawable.ic_videocam;
                 break;
+            case SHORTCUT_BLOCK_NUMBER:
+                text = resources.getString(R.string.search_shortcut_block_number);
+                drawableId = R.drawable.ic_not_interested_googblue_24dp;
+                break;
             default:
                 throw new IllegalArgumentException("Invalid shortcut type");
         }
diff --git a/src/com/android/dialer/list/RegularSearchListAdapter.java b/src/com/android/dialer/list/RegularSearchListAdapter.java
index f431e6a..748f4dc 100644
--- a/src/com/android/dialer/list/RegularSearchListAdapter.java
+++ b/src/com/android/dialer/list/RegularSearchListAdapter.java
@@ -31,7 +31,7 @@
  * List adapter to display regular search results.
  */
 public class RegularSearchListAdapter extends DialerPhoneNumberListAdapter {
-    private boolean mIsQuerySipAddress;
+    protected boolean mIsQuerySipAddress;
 
     public RegularSearchListAdapter(Context context) {
         super(context);
@@ -84,16 +84,20 @@
                 && hasDigitsInQueryString();
         mIsQuerySipAddress = PhoneNumberHelper.isUriNumber(queryString);
 
+        if (isChanged(showNumberShortcuts)) {
+            notifyDataSetChanged();
+        }
+        super.setQueryString(queryString);
+    }
+
+    protected boolean isChanged(boolean showNumberShortcuts) {
         boolean changed = false;
         changed |= setShortcutEnabled(SHORTCUT_DIRECT_CALL,
                 showNumberShortcuts || mIsQuerySipAddress);
         changed |= setShortcutEnabled(SHORTCUT_SEND_SMS_MESSAGE, showNumberShortcuts);
         changed |= setShortcutEnabled(SHORTCUT_MAKE_VIDEO_CALL,
                 showNumberShortcuts && CallUtil.isVideoEnabled(getContext()));
-        if (changed) {
-            notifyDataSetChanged();
-        }
-        super.setQueryString(queryString);
+        return changed;
     }
 
     /**
diff --git a/src/com/android/dialer/list/SearchFragment.java b/src/com/android/dialer/list/SearchFragment.java
index 26ed117..f75fa0f 100644
--- a/src/com/android/dialer/list/SearchFragment.java
+++ b/src/com/android/dialer/list/SearchFragment.java
@@ -106,8 +106,8 @@
         try {
             mActivityScrollListener = (OnListFragmentScrolledListener) activity;
         } catch (ClassCastException e) {
-            throw new ClassCastException(activity.toString()
-                    + " must implement OnListFragmentScrolledListener");
+            Log.d(TAG, activity.toString() + " doesn't implement OnListFragmentScrolledListener. " +
+                    "Ignoring.");
         }
     }
 
@@ -144,7 +144,9 @@
         listView.setOnScrollListener(new OnScrollListener() {
             @Override
             public void onScrollStateChanged(AbsListView view, int scrollState) {
-                mActivityScrollListener.onListFragmentScrollStateChange(scrollState);
+                if (mActivityScrollListener != null) {
+                    mActivityScrollListener.onListFragmentScrollStateChange(scrollState);
+                }
             }
 
             @Override