Prevent empty non-Indexable keys from being added

Change-Id: I688cd5243bb1651d60f74e168a84ddf8723816e3
Fixes: 37646265
Test: make RunSettingsRoboTests
diff --git a/src/com/android/settings/search/SettingsSearchIndexablesProvider.java b/src/com/android/settings/search/SettingsSearchIndexablesProvider.java
index b83f9fd..1bf0a15 100644
--- a/src/com/android/settings/search/SettingsSearchIndexablesProvider.java
+++ b/src/com/android/settings/search/SettingsSearchIndexablesProvider.java
@@ -26,6 +26,7 @@
 import com.android.settings.search2.DatabaseIndexingUtils;
 
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 
@@ -102,12 +103,21 @@
             }
 
             List<String> providerNonIndexableKeys = provider.getNonIndexableKeys(context);
-            if (providerNonIndexableKeys != null && providerNonIndexableKeys.size() > 0) {
-                values.addAll(providerNonIndexableKeys);
+
+            if (providerNonIndexableKeys == null || providerNonIndexableKeys.isEmpty()) {
+                continue;
             }
+
+            if (providerNonIndexableKeys.removeAll(Collections.singleton(null))
+                    || providerNonIndexableKeys.removeAll(Collections.singleton(""))) {
+                Log.v(TAG, clazz.getName() + " tried to add an empty non-indexable key");
+            }
+
+            values.addAll(providerNonIndexableKeys);
         }
 
         for (String nik : values) {
+
             final Object[] ref = new Object[NON_INDEXABLES_KEYS_COLUMNS.length];
             ref[COLUMN_INDEX_NON_INDEXABLE_KEYS_KEY_VALUE] = nik;
             cursor.addRow(ref);
diff --git a/src/com/android/settings/search2/DatabaseIndexingManager.java b/src/com/android/settings/search2/DatabaseIndexingManager.java
index ccc5283..80ae54f 100644
--- a/src/com/android/settings/search2/DatabaseIndexingManager.java
+++ b/src/com/android/settings/search2/DatabaseIndexingManager.java
@@ -426,6 +426,13 @@
             if (count > 0) {
                 while (cursor.moveToNext()) {
                     final String key = cursor.getString(COLUMN_INDEX_NON_INDEXABLE_KEYS_KEY_VALUE);
+
+                    if (TextUtils.isEmpty(key) && Log.isLoggable(LOG_TAG, Log.VERBOSE)) {
+                        Log.v(LOG_TAG, "Empty non-indexable key from: "
+                                + packageContext.getPackageName());
+                        continue;
+                    }
+
                     result.add(key);
                 }
             }
diff --git a/tests/robotests/src/com/android/settings/search2/DatabaseIndexingManagerTest.java b/tests/robotests/src/com/android/settings/search2/DatabaseIndexingManagerTest.java
index 047d867..7bbda0f 100644
--- a/tests/robotests/src/com/android/settings/search2/DatabaseIndexingManagerTest.java
+++ b/tests/robotests/src/com/android/settings/search2/DatabaseIndexingManagerTest.java
@@ -31,9 +31,7 @@
 import android.database.sqlite.SQLiteDatabase;
 import android.net.Uri;
 import android.os.Build;
-import android.provider.SearchIndexableData;
 import android.provider.SearchIndexableResource;
-import android.provider.SearchIndexablesContract;
 import android.util.ArrayMap;
 import com.android.settings.R;
 import com.android.settings.SettingsRobolectricTestRunner;
@@ -62,6 +60,7 @@
 import java.util.Map;
 import java.util.Set;
 
+import static android.provider.SearchIndexablesContract.INDEXABLES_RAW_COLUMNS;
 import static com.google.common.truth.Truth.assertThat;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
@@ -69,6 +68,7 @@
 import static org.mockito.Matchers.anyMap;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -903,7 +903,7 @@
     }
 
     @Test
-    public void testUpdateDataInDatabase_DisabledResultsAreIndexable_BecomeEnabled() {
+    public void testUpdateDataInDatabase_disabledResultsAreIndexable_becomeEnabled() {
         // Both results are initially disabled, and then TITLE_TWO gets enabled.
         final boolean enabled = false;
         insertSpecialCase(TITLE_ONE, enabled, KEY_ONE);
@@ -921,6 +921,18 @@
         assertThat(cursor.getString(2)).isEqualTo(TITLE_TWO);
     }
 
+    @Test
+    @Config(shadows = {ShadowContentResolver.class})
+    public void testEmptyNonIndexableKeys_emptyDataKeyResources_addedToDatabase() {
+        insertSpecialCase(TITLE_ONE, true /* enabled */, null /* dataReferenceKey */);
+
+        mManager.updateDatabase(false, localeStr);
+
+        Cursor cursor = mDb.rawQuery("SELECT * FROM prefs_index WHERE enabled = 1", null);
+        cursor.moveToPosition(0);
+        assertThat(cursor.getCount()).isEqualTo(1);
+        assertThat(cursor.getString(2)).isEqualTo(TITLE_ONE);
+    }
     // Util functions
 
     private SearchIndexableRaw getFakeRaw() {
@@ -986,11 +998,11 @@
     // TODO move this method and its counterpart in CursorToSearchResultConverterTest into
     // a util class with public fields to assert values.
     private Cursor getDummyCursor() {
-        MatrixCursor cursor = new MatrixCursor(SearchIndexablesContract.INDEXABLES_RAW_COLUMNS);
+        MatrixCursor cursor = new MatrixCursor(INDEXABLES_RAW_COLUMNS);
         final String BLANK = "";
 
         ArrayList<String> item =
-                new ArrayList<>(SearchIndexablesContract.INDEXABLES_RAW_COLUMNS.length);
+                new ArrayList<>(INDEXABLES_RAW_COLUMNS.length);
         item.add("42"); // Rank
         item.add(TITLE_ONE); // Title
         item.add(BLANK); // Summary on
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowContentResolver.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowContentResolver.java
index 6ae695b..36f170a 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowContentResolver.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowContentResolver.java
@@ -19,9 +19,15 @@
 import android.content.ContentResolver;
 import android.content.SyncAdapterType;
 
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.net.Uri;
+import android.provider.SearchIndexablesContract;
 import org.robolectric.annotation.Implementation;
 import org.robolectric.annotation.Implements;
 
+import static android.provider.SearchIndexablesContract.INDEXABLES_RAW_COLUMNS;
+
 @Implements(ContentResolver.class)
 public class ShadowContentResolver {
 
@@ -29,4 +35,13 @@
     public static SyncAdapterType[] getSyncAdapterTypesAsUser(int userId) {
         return new SyncAdapterType[0];
     }
+
+    @Implementation
+    public final Cursor query(Uri uri, String[] projection, String selection,
+            String[] selectionArgs, String sortOrder) {
+        MatrixCursor cursor = new MatrixCursor(INDEXABLES_RAW_COLUMNS);
+        MatrixCursor.RowBuilder builder = cursor.newRow()
+                .add(SearchIndexablesContract.NonIndexableKey.COLUMN_KEY_VALUE, "");
+        return cursor;
+    }
 }