Merge "Remove custom layout for expandpreference."
diff --git a/src/com/android/settings/DisplaySettings.java b/src/com/android/settings/DisplaySettings.java
index 2bb79b1..a22d25c 100644
--- a/src/com/android/settings/DisplaySettings.java
+++ b/src/com/android/settings/DisplaySettings.java
@@ -52,6 +52,8 @@
     private static final String TAG = "DisplaySettings";
 
     public static final String KEY_AUTO_BRIGHTNESS = "auto_brightness";
+    public static final String KEY_DISPLAY_SIZE = "screen_zoom";
+
     private static final String KEY_SCREEN_TIMEOUT = "screen_timeout";
 
     @Override
@@ -125,6 +127,13 @@
                 }
 
                 @Override
+                public List<String> getNonIndexableKeys(Context context) {
+                    List<String> keys = super.getNonIndexableKeys(context);
+                    keys.add(KEY_DISPLAY_SIZE);
+                    return keys;
+                }
+
+                @Override
                 public List<PreferenceController> getPreferenceControllers(Context context) {
                     return buildPreferenceControllers(context, null);
                 }
diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java
index eb3e726..135f5ed 100644
--- a/src/com/android/settings/accessibility/AccessibilitySettings.java
+++ b/src/com/android/settings/accessibility/AccessibilitySettings.java
@@ -46,6 +46,7 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.view.RotationPolicy;
 import com.android.internal.view.RotationPolicy.RotationPolicyListener;
+import com.android.settings.DisplaySettings;
 import com.android.settings.R;
 import com.android.settings.SettingsPreferenceFragment;
 import com.android.settings.Utils;
@@ -721,7 +722,7 @@
             new BaseSearchIndexProvider() {
         @Override
         public List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) {
-            List<SearchIndexableRaw> indexables = new ArrayList<SearchIndexableRaw>();
+            List<SearchIndexableRaw> indexables = new ArrayList<>();
 
             PackageManager packageManager = context.getPackageManager();
             AccessibilityManager accessibilityManager =
@@ -763,5 +764,15 @@
             indexables.add(indexable);
             return indexables;
         }
+
+        @Override
+        public List<String> getNonIndexableKeys(Context context) {
+            List<String> keys = super.getNonIndexableKeys(context);
+            // Duplicates in Display
+            keys.add(FONT_SIZE_PREFERENCE_SCREEN);
+            keys.add(DisplaySettings.KEY_DISPLAY_SIZE);
+
+            return keys;
+        }
     };
 }
diff --git a/src/com/android/settings/applications/ManageApplications.java b/src/com/android/settings/applications/ManageApplications.java
index 965501f..cf44b0d 100644
--- a/src/com/android/settings/applications/ManageApplications.java
+++ b/src/com/android/settings/applications/ManageApplications.java
@@ -416,20 +416,28 @@
         if (mListType == LIST_TYPE_HIGH_POWER) {
             mFilterAdapter.enableFilter(FILTER_APPS_POWER_WHITELIST_ALL);
         }
-        if (mListType == LIST_TYPE_STORAGE) {
-            AppFilter filter = new VolumeFilter(mVolumeUuid);
-            if (mStorageType == STORAGE_TYPE_MUSIC) {
+        // Storage filters below.
+        mApplications.setOverrideFilter(getStorageFilter(mListType, mStorageType, mVolumeUuid));
+    }
+
+    @VisibleForTesting
+    static AppFilter getStorageFilter(int listType, int storageType, String volumeUuid) {
+        AppFilter filter = new VolumeFilter(volumeUuid);
+        if (listType == LIST_TYPE_STORAGE) {
+            if (storageType == STORAGE_TYPE_MUSIC) {
                 filter = new CompoundFilter(ApplicationsState.FILTER_AUDIO, filter);
             } else {
                 filter = new CompoundFilter(ApplicationsState.FILTER_OTHER_APPS, filter);
             }
-            mApplications.setOverrideFilter(filter);
+            return filter;
         }
-        if (mListType == LIST_TYPE_GAMES) {
-            mApplications.setOverrideFilter(ApplicationsState.FILTER_GAMES);
-        } else if (mListType == LIST_TYPE_MOVIES) {
-            mApplications.setOverrideFilter(ApplicationsState.FILTER_MOVIES);
+        if (listType == LIST_TYPE_GAMES) {
+            return new CompoundFilter(ApplicationsState.FILTER_GAMES, filter);
+        } else if (listType == LIST_TYPE_MOVIES) {
+            return new CompoundFilter(ApplicationsState.FILTER_MOVIES, filter);
         }
+
+        return filter;
     }
 
     private int getDefaultFilter() {
diff --git a/src/com/android/settings/dashboard/conditional/CellularDataCondition.java b/src/com/android/settings/dashboard/conditional/CellularDataCondition.java
index 523bfc4..6842422 100644
--- a/src/com/android/settings/dashboard/conditional/CellularDataCondition.java
+++ b/src/com/android/settings/dashboard/conditional/CellularDataCondition.java
@@ -105,8 +105,11 @@
         public void onReceive(Context context, Intent intent) {
             if (TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED.equals(
                     intent.getAction())) {
-                ConditionManager.get(context).getCondition(CellularDataCondition.class)
-                        .refreshState();
+                CellularDataCondition condition = ConditionManager.get(context).getCondition(
+                        CellularDataCondition.class);
+                if (condition != null) {
+                    condition.refreshState();
+                }
             }
         }
     }
diff --git a/src/com/android/settings/gestures/SwipeToNotificationPreferenceController.java b/src/com/android/settings/gestures/SwipeToNotificationPreferenceController.java
index 89d38a1..22b88fc 100644
--- a/src/com/android/settings/gestures/SwipeToNotificationPreferenceController.java
+++ b/src/com/android/settings/gestures/SwipeToNotificationPreferenceController.java
@@ -60,7 +60,7 @@
     @Override
     protected boolean isSwitchPrefEnabled() {
         return Settings.Secure.getInt(mContext.getContentResolver(),
-                Settings.Secure.SYSTEM_NAVIGATION_KEYS_ENABLED, 1)
+                Settings.Secure.SYSTEM_NAVIGATION_KEYS_ENABLED, 0)
                 == 1;
     }
 }
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 b39aa05..41952f3 100644
--- a/src/com/android/settings/search2/DatabaseIndexingManager.java
+++ b/src/com/android/settings/search2/DatabaseIndexingManager.java
@@ -428,6 +428,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/accessibility/AccessibilitySettingsTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java
new file mode 100644
index 0000000..4da06c0
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java
@@ -0,0 +1,34 @@
+package com.android.settings.accessibility;
+
+import android.content.Context;
+
+import com.android.settings.R;
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.XmlTestUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class AccessibilitySettingsTest {
+
+    @Test
+    public void testNonIndexableKeys_existInXmlLayout() {
+        final Context context = RuntimeEnvironment.application;
+        final List<String> niks = AccessibilitySettings.SEARCH_INDEX_DATA_PROVIDER
+                .getNonIndexableKeys(context);
+        final List<String> keys = new ArrayList<>();
+
+        keys.addAll(XmlTestUtils.getKeysFromPreferenceXml(context, R.xml.accessibility_settings));
+
+        assertThat(keys).containsAllIn(niks);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/search/DataIntegrityTest.java b/tests/robotests/src/com/android/settings/search/DataIntegrityTest.java
index f10752a..6ffd704 100644
--- a/tests/robotests/src/com/android/settings/search/DataIntegrityTest.java
+++ b/tests/robotests/src/com/android/settings/search/DataIntegrityTest.java
@@ -93,10 +93,7 @@
         for (Integer xmlResId : xmlList) {
             // Get all keys to be indexed
             final List<String> prefKeys = XmlTestUtils.getKeysFromPreferenceXml(context, xmlResId);
-
             pageKeys.addAll(prefKeys);
-            // Remove grandfathered keys.
-            pageKeys.removeAll(grandfatheredKeys);
             // Find all already-existing keys.
             pageKeys.retainAll(masterKeys);
             // Keep list of offending duplicate keys.
@@ -105,7 +102,7 @@
             masterKeys.addAll(prefKeys);
             pageKeys.clear();
         }
-        assertThat(duplicateKeys).isEmpty();
+        assertThat(duplicateKeys).containsExactlyElementsIn(grandfatheredKeys);
     }
 
     /**
diff --git a/tests/robotests/src/com/android/settings/search2/DatabaseIndexingManagerTest.java b/tests/robotests/src/com/android/settings/search2/DatabaseIndexingManagerTest.java
index 0d24eb4..7a6dc57 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;
@@ -927,7 +927,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);
@@ -945,6 +945,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() {
@@ -1010,11 +1022,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;
+    }
 }
diff --git a/tests/unit/src/com/android/settings/applications/ManageApplicationsTest.java b/tests/unit/src/com/android/settings/applications/ManageApplicationsTest.java
new file mode 100644
index 0000000..92ea22f
--- /dev/null
+++ b/tests/unit/src/com/android/settings/applications/ManageApplicationsTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2017 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.settings.applications;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+
+import android.content.pm.ApplicationInfo;
+
+import com.android.settingslib.applications.ApplicationsState;
+
+import org.junit.Test;
+
+public class ManageApplicationsTest {
+    @Test
+    public void getStorageFilter_filtersVolumeForAudio() {
+        ApplicationsState.AppFilter filter =
+                ManageApplications.getStorageFilter(
+                        ManageApplications.LIST_TYPE_STORAGE,
+                        ManageApplications.STORAGE_TYPE_MUSIC,
+                        "uuid");
+        final ApplicationInfo info = new ApplicationInfo();
+        info.volumeUuid = "uuid";
+        info.category = ApplicationInfo.CATEGORY_AUDIO;
+        final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class);
+        appEntry.info = info;
+
+        assertThat(filter.filterApp(appEntry)).isTrue();
+    }
+
+    @Test
+    public void getStorageFilter_filtersVolumeForVideo() {
+        ApplicationsState.AppFilter filter =
+                ManageApplications.getStorageFilter(
+                        ManageApplications.LIST_TYPE_MOVIES,
+                        ManageApplications.STORAGE_TYPE_DEFAULT,
+                        "uuid");
+        final ApplicationInfo info = new ApplicationInfo();
+        info.volumeUuid = "uuid";
+        info.category = ApplicationInfo.CATEGORY_VIDEO;
+        final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class);
+        appEntry.info = info;
+
+        assertThat(filter.filterApp(appEntry)).isTrue();
+    }
+
+    @Test
+    public void getStorageFilter_filtersVolumeForGames() {
+        ApplicationsState.AppFilter filter =
+                ManageApplications.getStorageFilter(
+                        ManageApplications.LIST_TYPE_GAMES,
+                        ManageApplications.STORAGE_TYPE_DEFAULT,
+                        "uuid");
+        final ApplicationInfo info = new ApplicationInfo();
+        info.volumeUuid = "uuid";
+        info.category = ApplicationInfo.CATEGORY_GAME;
+        final ApplicationsState.AppEntry appEntry = mock(ApplicationsState.AppEntry.class);
+        appEntry.info = info;
+
+        assertThat(filter.filterApp(appEntry)).isTrue();
+    }
+}