Merge "Remove the app header from ManageApplications when used for storage."
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 776c4ec..b04182f2 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -3092,7 +3092,7 @@
         </activity-alias>
 
         <activity android:name=".Settings$StorageDashboardActivity"
-                  android:label="@string/storage_settings_2"
+                  android:label="@string/storage_settings"
                   android:icon="@drawable/ic_settings_storage">
             <intent-filter android:priority="5">
                 <action android:name="com.android.settings.action.SETTINGS" />
diff --git a/res/layout/system_info_list_item.xml b/res/layout/system_info_list_item.xml
new file mode 100644
index 0000000..37806bd
--- /dev/null
+++ b/res/layout/system_info_list_item.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="?android:attr/listPreferredItemHeight"
+    android:orientation="vertical"
+    android:paddingStart="?android:attr/dialogPreferredPadding"
+    android:paddingEnd="?android:attr/dialogPreferredPadding"
+    android:paddingTop="8dp"
+    android:paddingBottom="8dp">
+    <TextView
+        android:id="@+id/title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:singleLine="true"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:ellipsize="marquee"
+        android:fadingEdge="horizontal"/>
+    <TextView
+        android:id="@+id/summary"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/title"
+        android:layout_alignStart="@id/title"
+        android:textAppearance="?android:attr/textAppearanceSmall"
+        android:textColor="?android:attr/textColorSecondary"
+        android:maxLines="4"/>
+</LinearLayout>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 0f8f762..b9e9c1c 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -8019,7 +8019,4 @@
     <!-- Preference label for the Files storage section. [CHAR LIMIT=50] -->
     <string name="storage_files">Files</string>
 
-    <!-- Main settings screen item's title to go into the storage settings screen [CHAR LIMIT=25] -->
-    <string name="storage_settings_2" >Phone Storage</string>
-
 </resources>
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index 06941d0..d779f3e 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -50,7 +50,6 @@
     public static class LocalePickerActivity extends SettingsActivity { /* empty */ }
     public static class LanguageAndRegionSettingsActivity extends SettingsActivity { /* empty */ }
     public static class UserDictionarySettingsActivity extends SettingsActivity { /* empty */ }
-    public static class HomeSettingsActivity extends SettingsActivity { /* empty */ }
     public static class DisplaySettingsActivity extends SettingsActivity { /* empty */ }
     public static class NightDisplaySettingsActivity extends SettingsActivity { /* empty */ }
     public static class DeviceInfoSettingsActivity extends SettingsActivity { /* empty */ }
diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java
index 2ca0d4b..0751b81 100644
--- a/src/com/android/settings/SettingsActivity.java
+++ b/src/com/android/settings/SettingsActivity.java
@@ -165,64 +165,6 @@
     private CharSequence mInitialTitle;
     private int mInitialTitleResId;
 
-    // Show only these settings for restricted users
-    private String[] SETTINGS_FOR_RESTRICTED = {
-            //wireless_section
-            WifiSettingsActivity.class.getName(),
-            Settings.BluetoothSettingsActivity.class.getName(),
-            Settings.DataUsageSummaryActivity.class.getName(),
-            Settings.SimSettingsActivity.class.getName(),
-            Settings.WirelessSettingsActivity.class.getName(),
-            //device_section
-            Settings.HomeSettingsActivity.class.getName(),
-            Settings.SoundSettingsActivity.class.getName(),
-            Settings.DisplaySettingsActivity.class.getName(),
-            Settings.StorageSettingsActivity.class.getName(),
-            Settings.ManageApplicationsActivity.class.getName(),
-            Settings.PowerUsageSummaryActivity.class.getName(),
-            Settings.GestureSettingsActivity.class.getName(),
-            //personal_section
-            Settings.LocationSettingsActivity.class.getName(),
-            Settings.SecuritySettingsActivity.class.getName(),
-            Settings.InputMethodAndLanguageSettingsActivity.class.getName(),
-            Settings.UserSettingsActivity.class.getName(),
-            Settings.AccountSettingsActivity.class.getName(),
-            //system_section
-            Settings.DateTimeSettingsActivity.class.getName(),
-            Settings.DeviceInfoSettingsActivity.class.getName(),
-            Settings.AccessibilitySettingsActivity.class.getName(),
-            Settings.PrintSettingsActivity.class.getName(),
-            Settings.PaymentSettingsActivity.class.getName(),
-            Settings.EnterprisePrivacySettingsActivity.class.getName(),
-
-            // New IA
-            // Home page
-            Settings.NetworkDashboardActivity.class.getName(),
-            Settings.ConnectedDeviceDashboardActivity.class.getName(),
-            Settings.AppAndNotificationDashboardActivity.class.getName(),
-            "com.android.settings.Settings.BatteryDashboardAlias",
-            "com.android.settings.Settings.DisplayDashboardAlias",
-            "com.android.settings.Settings.SoundDashboardAlias",
-            "com.android.settings.Settings.SecurityDashboardAlias",
-            Settings.UserAndAccountDashboardActivity.class.getName(),
-            Settings.SystemDashboardActivity.class.getName(),
-            Settings.SupportDashboardActivity.class.getName(),
-            // Home page > Apps & Notifications
-            "com.android.settings.Settings.ManageApplicationsDashboardAlias",
-            "com.android.settings.Settings.PaymentSettingsDashboardAlias",
-            // Home page > Network & Internet
-            "com.android.settings.Settings.WifiDashboardAlias",
-            "com.android.settings.Settings.DataUsageDashboardAlias",
-            // Home page > Security
-            "com.android.settings.Settings.LocationDashboardAlias",
-            // Home page > System
-            Settings.LanguageAndRegionSettingsActivity.class.getName(),
-            Settings.InputAndGestureSettingsActivity.class.getName(),
-            "com.android.settings.Settings.DateTimeDashboardAlias",
-            "com.android.settings.Settings.AccessibilityDashboardAlias",
-            "com.android.settings.Settings.AboutDeviceDashboardAlias",
-    };
-
     private static final String[] LIKE_SHORTCUT_INTENT_ACTION_ARRAY = {
             "android.settings.APPLICATION_DETAILS_SETTINGS"
     };
@@ -1009,8 +951,10 @@
             for (DashboardCategory category : categories) {
                 for (Tile tile : category.tiles) {
                     ComponentName component = tile.intent.getComponent();
-                    if (packageName.equals(component.getPackageName()) && !ArrayUtils.contains(
-                            SETTINGS_FOR_RESTRICTED, component.getClassName())) {
+                    final String name = component.getClassName();
+                    final boolean isEnabledForRestricted = ArrayUtils.contains(
+                            SettingsGateway.SETTINGS_FOR_RESTRICTED, name);
+                    if (packageName.equals(component.getPackageName()) && !isEnabledForRestricted) {
                         setTileEnabled(component, false, isAdmin);
                     }
                 }
@@ -1055,7 +999,8 @@
 
     private void setTileEnabled(ComponentName component, boolean enabled, boolean isAdmin) {
         if (UserHandle.MU_ENABLED && !isAdmin && getPackageName().equals(component.getPackageName())
-                && !ArrayUtils.contains(SETTINGS_FOR_RESTRICTED, component.getClassName())) {
+                && !ArrayUtils.contains(SettingsGateway.SETTINGS_FOR_RESTRICTED,
+                component.getClassName())) {
             enabled = false;
         }
         setTileEnabled(component, enabled);
diff --git a/src/com/android/settings/accounts/AccountPreferenceController.java b/src/com/android/settings/accounts/AccountPreferenceController.java
index ad3fac1..0ddd366 100644
--- a/src/com/android/settings/accounts/AccountPreferenceController.java
+++ b/src/com/android/settings/accounts/AccountPreferenceController.java
@@ -311,7 +311,10 @@
             preferenceGroup.setContentDescription(
                 mContext.getString(R.string.accessibility_category_personal));
         }
-        mParent.getPreferenceScreen().addPreference(preferenceGroup);
+        final PreferenceScreen screen = mParent.getPreferenceScreen();
+        if (screen != null) {
+            screen.addPreference(preferenceGroup);
+        }
         profileData.preferenceGroup = preferenceGroup;
         if (userInfo.isEnabled()) {
             profileData.authenticatorHelper = new AuthenticatorHelper(context,
@@ -367,6 +370,9 @@
 
     void cleanUpPreferences() {
         PreferenceScreen screen = mParent.getPreferenceScreen();
+        if (screen == null) {
+            return;
+        }
         for (int i = 0; i < mProfiles.size(); i++) {
             final PreferenceGroup preferenceGroup = mProfiles.valueAt(i).preferenceGroup;
             screen.removePreference(preferenceGroup);
diff --git a/src/com/android/settings/applications/InstalledAppDetails.java b/src/com/android/settings/applications/InstalledAppDetails.java
index d689ee4..b5f0e76 100755
--- a/src/com/android/settings/applications/InstalledAppDetails.java
+++ b/src/com/android/settings/applications/InstalledAppDetails.java
@@ -324,7 +324,12 @@
                 ? R.xml.installed_app_details_ia
                 : R.xml.installed_app_details);
         addDynamicPrefs();
-
+        if (mDashboardFeatureProvider.isEnabled()) {
+            mFooter = new LayoutPreference(getPrefContext(), R.layout.app_action_buttons);
+            mFooter.setOrder(10000);
+            mFooter.setKey(KEY_FOOTER);
+            getPreferenceScreen().addPreference(mFooter);
+        }
         if (Utils.isBandwidthControlEnabled()) {
             INetworkStatsService statsService = INetworkStatsService.Stub.asInterface(
                     ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
@@ -964,12 +969,6 @@
         }
 
         addAppInstallerInfoPref(screen);
-        if (mDashboardFeatureProvider.isEnabled()) {
-            mFooter = new LayoutPreference(screen.getContext(), R.layout.app_action_buttons);
-            mFooter.setOrder(10000);
-            mFooter.setKey(KEY_FOOTER);
-            screen.addPreference(mFooter);
-        }
     }
 
     private void addAppInstallerInfoPref(PreferenceScreen screen) {
diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java
index db7eb5a..637fcd5 100644
--- a/src/com/android/settings/core/gateway/SettingsGateway.java
+++ b/src/com/android/settings/core/gateway/SettingsGateway.java
@@ -32,6 +32,7 @@
 import com.android.settings.MasterClear;
 import com.android.settings.PrivacySettings;
 import com.android.settings.SecuritySettings;
+import com.android.settings.Settings;
 import com.android.settings.TestingSettings;
 import com.android.settings.TetherSettings;
 import com.android.settings.TrustedCredentialsSettings;
@@ -244,4 +245,60 @@
             UserAndAccountDashboardFragment.class.getName(),
             EnterprisePrivacySettings.class.getName(),
     };
+
+    public static final String[] SETTINGS_FOR_RESTRICTED = {
+            //wireless_section
+            Settings.WifiSettingsActivity.class.getName(),
+            Settings.BluetoothSettingsActivity.class.getName(),
+            Settings.DataUsageSummaryActivity.class.getName(),
+            Settings.SimSettingsActivity.class.getName(),
+            Settings.WirelessSettingsActivity.class.getName(),
+            //device_section
+            Settings.SoundSettingsActivity.class.getName(),
+            Settings.DisplaySettingsActivity.class.getName(),
+            Settings.StorageSettingsActivity.class.getName(),
+            Settings.ManageApplicationsActivity.class.getName(),
+            Settings.PowerUsageSummaryActivity.class.getName(),
+            Settings.GestureSettingsActivity.class.getName(),
+            //personal_section
+            Settings.LocationSettingsActivity.class.getName(),
+            Settings.SecuritySettingsActivity.class.getName(),
+            Settings.InputMethodAndLanguageSettingsActivity.class.getName(),
+            Settings.UserSettingsActivity.class.getName(),
+            Settings.AccountSettingsActivity.class.getName(),
+            //system_section
+            Settings.DateTimeSettingsActivity.class.getName(),
+            Settings.DeviceInfoSettingsActivity.class.getName(),
+            Settings.AccessibilitySettingsActivity.class.getName(),
+            Settings.PrintSettingsActivity.class.getName(),
+            Settings.PaymentSettingsActivity.class.getName(),
+            Settings.EnterprisePrivacySettingsActivity.class.getName(),
+
+            // New IA
+            // Home page
+            Settings.NetworkDashboardActivity.class.getName(),
+            Settings.ConnectedDeviceDashboardActivity.class.getName(),
+            Settings.AppAndNotificationDashboardActivity.class.getName(),
+            "com.android.settings.BatteryDashboardAlias",
+            "com.android.settings.DisplayDashboardAlias",
+            "com.android.settings.SoundDashboardAlias",
+            "com.android.settings.SecurityDashboardAlias",
+            Settings.UserAndAccountDashboardActivity.class.getName(),
+            Settings.SystemDashboardActivity.class.getName(),
+            Settings.SupportDashboardActivity.class.getName(),
+            // Home page > Apps & Notifications
+            "com.android.settings.ManageApplicationsDashboardAlias",
+            "com.android.settings.PaymentSettingsDashboardAlias",
+            // Home page > Network & Internet
+            "com.android.settings.WifiDashboardAlias",
+            "com.android.settings.DataUsageDashboardAlias",
+            // Home page > Security
+            "com.android.settings.LocationDashboardAlias",
+            // Home page > System
+            Settings.LanguageAndRegionSettingsActivity.class.getName(),
+            Settings.InputAndGestureSettingsActivity.class.getName(),
+            "com.android.settings.DateTimeDashboardAlias",
+            "com.android.settings.AccessibilityDashboardAlias",
+            "com.android.settings.AboutDeviceDashboardAlias",
+    };
 }
diff --git a/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java b/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java
index e63a1df..b0a9902 100644
--- a/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java
+++ b/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java
@@ -636,12 +636,11 @@
             final long usedSize = mTotalSize - details.availSize;
             final long unaccountedSize = usedSize - accountedSize;
             final long otherSize = totalMiscSize + totalDownloadsSize + unaccountedSize;
-            if (LOGV)
-                Log.v(TAG, "Other items: \n\tmTotalSize: " + mTotalSize + " availSize: "
-                        + details.availSize + " usedSize: " + usedSize + "\n\taccountedSize: "
-                        + accountedSize + " unaccountedSize size: " + unaccountedSize
-                        + "\n\ttotalMiscSize: " + totalMiscSize + " totalDownloadsSize: "
-                        + totalDownloadsSize + "\n\tdetails: " + details);
+            Log.v(TAG, "Other items: \n\tmTotalSize: " + mTotalSize + " availSize: "
+                    + details.availSize + " usedSize: " + usedSize + "\n\taccountedSize: "
+                    + accountedSize + " unaccountedSize size: " + unaccountedSize
+                    + "\n\ttotalMiscSize: " + totalMiscSize + " totalDownloadsSize: "
+                    + totalDownloadsSize + "\n\tdetails: " + details);
             updatePreference(otherItem, otherSize);
         }
     }
diff --git a/src/com/android/settings/search2/CursorToSearchResultConverter.java b/src/com/android/settings/search2/CursorToSearchResultConverter.java
index 3d29323..3255c0c 100644
--- a/src/com/android/settings/search2/CursorToSearchResultConverter.java
+++ b/src/com/android/settings/search2/CursorToSearchResultConverter.java
@@ -35,10 +35,12 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
-import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_RANK;
+import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_ID;
 import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_TITLE;
 import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_SUMMARY_ON;
 import static com.android.settings.search2.DatabaseResultLoader.COLUMN_INDEX_CLASS_NAME;
@@ -63,21 +65,28 @@
 
     private final String TAG = "CursorConverter";
 
+    private final String mQueryText;
+
     private final Context mContext;
 
-    public CursorToSearchResultConverter(Context context) {
+    private final Set<String> mKeys;
+
+    public CursorToSearchResultConverter(Context context, String queryText) {
         mContext = context;
+        mKeys = new HashSet<>();
+        mQueryText = queryText;
     }
 
-    public List<SearchResult> convertCursor(Cursor cursorResults) {
+    public List<SearchResult> convertCursor(Cursor cursorResults, int baseRank) {
         if (cursorResults == null) {
             return null;
         }
         final Map<String, Context> contextMap = new HashMap<>();
-        final ArrayList<SearchResult> results = new ArrayList<>();
+        final List<SearchResult> results = new ArrayList<>();
 
         while (cursorResults.moveToNext()) {
-            SearchResult result = buildSingleSearchResultFromCursor(contextMap, cursorResults);
+            SearchResult result = buildSingleSearchResultFromCursor(contextMap, cursorResults,
+                    baseRank);
             if (result != null) {
                 results.add(result);
             }
@@ -87,13 +96,22 @@
     }
 
     private SearchResult buildSingleSearchResultFromCursor(Map<String, Context> contextMap,
-            Cursor cursor) {
+            Cursor cursor, int baseRank) {
+        final String docId = cursor.getString(COLUMN_INDEX_ID);
+        /* Make sure that this result has not yet been added as a result. Checking the docID
+           covers the case of multiple queries matching the same row, but we need to also to check
+           for potentially the same named or slightly varied names pointing to the same page.
+         */
+        if (mKeys.contains(docId)) {
+            return null;
+        }
+        mKeys.add(docId);
+
         final String pkgName = cursor.getString(COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE);
         final String action = cursor.getString(COLUMN_INDEX_INTENT_ACTION);
         final String title = cursor.getString(COLUMN_INDEX_TITLE);
         final String summaryOn = cursor.getString(COLUMN_INDEX_SUMMARY_ON);
         final String className = cursor.getString(COLUMN_INDEX_CLASS_NAME);
-        final int rank = cursor.getInt(COLUMN_INDEX_RANK);
         final String key = cursor.getString(COLUMN_INDEX_KEY);
         final String iconResStr = cursor.getString(COLUMN_INDEX_ICON);
         final int payloadType = cursor.getInt(COLUMN_INDEX_PAYLOAD_TYPE);
@@ -109,9 +127,13 @@
             return null;
         }
 
+        final List<String> breadcrumbs = getBreadcrumbs(cursor);
+        final int rank = getRank(breadcrumbs, baseRank);
+
         final SearchResult.Builder builder = new SearchResult.Builder();
         builder.addTitle(title)
                 .addSummary(summaryOn)
+                .addBreadcrumbs(breadcrumbs)
                 .addRank(rank)
                 .addIcon(getIconForPackage(contextMap, pkgName, className, iconResStr))
                 .addPayload(payload);
@@ -187,4 +209,24 @@
         }
         return null;
     }
+
+    private List<String> getBreadcrumbs(Cursor cursor) {
+        return new ArrayList<>();
+    }
+
+    /** Uses the breadcrumbs to determine the offset to the base rank.
+     *  There are two checks
+     *  A) If the query matches the highest level menu title
+     *  B) If the query matches a subsequent menu title
+     *
+     *  If the query matches A and B, the offset is 0.
+     *  If the query matches A only, the offset is 1.
+     *  If the query matches neither A nor B, the offset is 2.
+     * @param crumbs from the Information Architecture
+     * @param baseRank of the result. Lower if it's a better result.
+     * @return
+     */
+    private int getRank(List<String> crumbs, int baseRank) {
+        return baseRank;
+    }
 }
diff --git a/src/com/android/settings/search2/DatabaseIndexingManager.java b/src/com/android/settings/search2/DatabaseIndexingManager.java
index fa482ef..e29ffeb 100644
--- a/src/com/android/settings/search2/DatabaseIndexingManager.java
+++ b/src/com/android/settings/search2/DatabaseIndexingManager.java
@@ -108,15 +108,15 @@
         public boolean fullIndex;
 
         public UpdateData() {
-            dataToUpdate = new ArrayList<SearchIndexableData>();
-            dataToDelete = new ArrayList<SearchIndexableData>();
-            nonIndexableKeys = new HashMap<String, List<String>>();
+            dataToUpdate = new ArrayList<>();
+            dataToDelete = new ArrayList<>();
+            nonIndexableKeys = new HashMap<>();
         }
 
         public UpdateData(DatabaseIndexingManager.UpdateData other) {
-            dataToUpdate = new ArrayList<SearchIndexableData>(other.dataToUpdate);
-            dataToDelete = new ArrayList<SearchIndexableData>(other.dataToDelete);
-            nonIndexableKeys = new HashMap<String, List<String>>(other.nonIndexableKeys);
+            dataToUpdate = new ArrayList<>(other.dataToUpdate);
+            dataToDelete = new ArrayList<>(other.dataToDelete);
+            nonIndexableKeys = new HashMap<>(other.nonIndexableKeys);
             forceUpdate = other.forceUpdate;
             fullIndex = other.fullIndex;
         }
diff --git a/src/com/android/settings/search2/DatabaseResultLoader.java b/src/com/android/settings/search2/DatabaseResultLoader.java
index 201d76f..f7acd25 100644
--- a/src/com/android/settings/search2/DatabaseResultLoader.java
+++ b/src/com/android/settings/search2/DatabaseResultLoader.java
@@ -16,31 +16,19 @@
 
 package com.android.settings.search2;
 
-import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.support.annotation.VisibleForTesting;
-import android.text.TextUtils;
-import android.util.Log;
 
-import com.android.settings.SettingsActivity;
-import com.android.settings.Utils;
-import com.android.settings.search.Index;
 import com.android.settings.search.IndexDatabaseHelper;
 import com.android.settings.utils.AsyncLoader;
 
 import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
+import java.util.Arrays;
 import java.util.List;
-import java.util.Map;
 
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns;
+import static com.android.settings.search.IndexDatabaseHelper.Tables.TABLE_PREFS_INDEX;
 
 /**
  * AsyncTask to retrieve Settings, First party app and any intent based results.
@@ -54,30 +42,68 @@
     private final CursorToSearchResultConverter mConverter;
 
     /* These indices are used to match the columns of the this loader's SELECT statement.
-     These are not necessarily the same order or coverage as the schema defined in
+     These are not necessarily the same order nor similar coverage as the schema defined in
      IndexDatabaseHelper */
-    public static final int COLUMN_INDEX_RANK = 0;
-    public static final int COLUMN_INDEX_TITLE = 1;
-    public static final int COLUMN_INDEX_SUMMARY_ON = 2;
-    public static final int COLUMN_INDEX_SUMMARY_OFF = 3;
-    public static final int COLUMN_INDEX_ENTRIES = 4;
-    public static final int COLUMN_INDEX_KEYWORDS = 5;
-    public static final int COLUMN_INDEX_CLASS_NAME = 6;
-    public static final int COLUMN_INDEX_SCREEN_TITLE = 7;
-    public static final int COLUMN_INDEX_ICON = 8;
-    public static final int COLUMN_INDEX_INTENT_ACTION = 9;
-    public static final int COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE = 10;
-    public static final int COLUMN_INDEX_INTENT_ACTION_TARGET_CLASS = 11;
-    public static final int COLUMN_INDEX_ENABLED = 12;
-    public static final int COLUMN_INDEX_KEY = 13;
-    public static final int COLUMN_INDEX_PAYLOAD_TYPE = 14;
-    public static final int COLUMN_INDEX_PAYLOAD = 15;
+    static final int COLUMN_INDEX_ID = 0;
+    static final int COLUMN_INDEX_TITLE = 1;
+    static final int COLUMN_INDEX_SUMMARY_ON = 2;
+    static final int COLUMN_INDEX_SUMMARY_OFF = 3;
+    static final int COLUMN_INDEX_CLASS_NAME = 4;
+    static final int COLUMN_INDEX_SCREEN_TITLE = 5;
+    static final int COLUMN_INDEX_ICON = 6;
+    static final int COLUMN_INDEX_INTENT_ACTION = 7;
+    static final int COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE = 8;
+    static final int COLUMN_INDEX_INTENT_ACTION_TARGET_CLASS = 9;
+    static final int COLUMN_INDEX_KEY = 10;
+    static final int COLUMN_INDEX_PAYLOAD_TYPE = 11;
+    static final int COLUMN_INDEX_PAYLOAD = 12;
+
+    public static final String[] SELECT_COLUMNS = {
+            IndexColumns.DOCID,
+            IndexColumns.DATA_TITLE,
+            IndexColumns.DATA_SUMMARY_ON,
+            IndexColumns.DATA_SUMMARY_OFF,
+            IndexColumns.CLASS_NAME,
+            IndexColumns.SCREEN_TITLE,
+            IndexColumns.ICON,
+            IndexColumns.INTENT_ACTION,
+            IndexColumns.INTENT_TARGET_PACKAGE,
+            IndexColumns.INTENT_TARGET_CLASS,
+            IndexColumns.DATA_KEY_REF,
+            IndexColumns.PAYLOAD_TYPE,
+            IndexColumns.PAYLOAD
+    };
+
+    public static final String[] MATCH_COLUMNS_PRIMARY = {
+            IndexColumns.DATA_TITLE,
+            IndexColumns.DATA_TITLE_NORMALIZED,
+    };
+
+    public static final String[] MATCH_COLUMNS_SECONDARY = {
+            IndexColumns.DATA_SUMMARY_ON,
+            IndexColumns.DATA_SUMMARY_ON_NORMALIZED,
+            IndexColumns.DATA_SUMMARY_OFF,
+            IndexColumns.DATA_SUMMARY_OFF_NORMALIZED,
+    };
+
+    public static final String[] MATCH_COLUMNS_TERTIARY = {
+            IndexColumns.DATA_KEYWORDS,
+            IndexColumns.DATA_ENTRIES
+    };
+
+    /**
+     * Base ranks defines the best possible rank based on what the query matches.
+     * If the query matches the title, the best rank it can be is 1
+     * If the query only matches the summary, the best rank it can be is 4
+     * If the query only matches keywords or entries, the best rank it can be is 7
+     */
+    private static final int[] BASE_RANKS = {1, 4, 7};
 
     public DatabaseResultLoader(Context context, String queryText) {
         super(context);
         mDatabase = IndexDatabaseHelper.getInstance(context).getReadableDatabase();
-        mQueryText = queryText;
-        mConverter = new CursorToSearchResultConverter(context);
+        mQueryText = cleanQuery(queryText);
+        mConverter = new CursorToSearchResultConverter(context, mQueryText);
     }
 
     @Override
@@ -91,10 +117,34 @@
             return null;
         }
 
-        String query = getSQLQuery();
-        Cursor result = mDatabase.rawQuery(query, null);
+        final List<SearchResult> primaryResults;
+        final List<SearchResult> secondaryResults;
+        final List<SearchResult> tertiaryResults;
 
-        return mConverter.convertCursor(result);
+        primaryResults = query(MATCH_COLUMNS_PRIMARY, BASE_RANKS[0]);
+        secondaryResults = query(MATCH_COLUMNS_SECONDARY, BASE_RANKS[1]);
+        tertiaryResults = query(MATCH_COLUMNS_TERTIARY, BASE_RANKS[2]);
+
+
+        final List<SearchResult> results = new ArrayList<>(primaryResults.size()
+                + secondaryResults.size()
+                + tertiaryResults.size());
+
+        results.addAll(primaryResults);
+        results.addAll(secondaryResults);
+        results.addAll(tertiaryResults);
+        return results;
+    }
+
+    private List<SearchResult> query(String[] matchColumns, int baseRank) {
+        final String whereClause = buildWhereClause(matchColumns);
+        final String[] selection = new String[matchColumns.length];
+        final String query = "%" + mQueryText + "%";
+        Arrays.fill(selection, query);
+
+        final Cursor resultCursor = mDatabase.query(TABLE_PREFS_INDEX, SELECT_COLUMNS, whereClause,
+                selection, null, null, null);
+        return mConverter.convertCursor(resultCursor, baseRank);
     }
 
     @Override
@@ -103,17 +153,24 @@
         return super.onCancelLoad();
     }
 
-    protected String getSQLQuery() {
-        return String.format("SELECT data_rank, data_title, data_summary_on, " +
-                        "data_summary_off, data_entries, data_keywords, class_name, screen_title,"
-                        + " icon, " +
-                        "intent_action, intent_target_package, intent_target_class, enabled, " +
-                        "data_key_reference, payload_type, payload FROM prefs_index WHERE prefs_index MATCH "
-                        + "'data_title:%s* " +
-                        "OR data_title_normalized:%s* OR data_keywords:%s*' AND locale = 'en_US'",
-                mQueryText, mQueryText, mQueryText);
+    /**
+     * A generic method to make the query suitable for searching the database.
+     * @return the cleaned query string
+     */
+    private static String cleanQuery(String query) {
+        return query.trim();
     }
 
-
-
+    private static String buildWhereClause(String[] matchColumns) {
+        StringBuilder sb = new StringBuilder(" ");
+        final int count = matchColumns.length;
+        for (int n = 0; n < count; n++) {
+            sb.append(matchColumns[n]);
+            sb.append(" like ?");
+            if (n < count - 1) {
+                sb.append(" OR ");
+            }
+        }
+        return sb.toString();
+    }
 }
diff --git a/src/com/android/settings/search2/SearchResult.java b/src/com/android/settings/search2/SearchResult.java
index 5bf757f..e817a9d 100644
--- a/src/com/android/settings/search2/SearchResult.java
+++ b/src/com/android/settings/search2/SearchResult.java
@@ -18,7 +18,7 @@
 
 import android.graphics.drawable.Drawable;
 
-import java.util.ArrayList;
+import java.util.List;
 import java.util.Objects;
 
 /**
@@ -42,7 +42,7 @@
      * An ordered list of the information hierarchy.
      * Intent Results: Displayed a hierarchy of selections to reach the setting from the home screen
      */
-    public final ArrayList<String> breadcrumbs;
+    public final List<String> breadcrumbs;
 
     /**
      * A suggestion for the ranking of the result.
@@ -96,7 +96,7 @@
     public static class Builder {
         protected CharSequence mTitle;
         protected CharSequence mSummary;
-        protected ArrayList<String> mBreadcrumbs;
+        protected List<String> mBreadcrumbs;
         protected int mRank = 42;
         protected ResultPayload mResultPayload;
         protected Drawable mIcon;
@@ -111,7 +111,7 @@
             return this;
         }
 
-        public Builder addBreadcrumbs(ArrayList<String> breadcrumbs) {
+        public Builder addBreadcrumbs(List<String> breadcrumbs) {
             mBreadcrumbs = breadcrumbs;
             return this;
         }
diff --git a/src/com/android/settings/wifi/AdvancedWifiSettings.java b/src/com/android/settings/wifi/AdvancedWifiSettings.java
index f7cc772..4727428 100644
--- a/src/com/android/settings/wifi/AdvancedWifiSettings.java
+++ b/src/com/android/settings/wifi/AdvancedWifiSettings.java
@@ -18,8 +18,11 @@
 
 import android.app.Dialog;
 import android.app.DialogFragment;
+import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.wifi.WifiManager;
 import android.net.wifi.WpsInfo;
 import android.os.Bundle;
 import android.os.UserManager;
@@ -44,6 +47,13 @@
 
     private boolean mUnavailable;
 
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            initPreferences();
+        }
+    };
+
     public AdvancedWifiSettings() {
         super(UserManager.DISALLOW_CONFIG_WIFI);
     }
@@ -74,13 +84,23 @@
     }
 
     @Override
-    public void onResume() {
-        super.onResume();
+    public void onStart() {
+        super.onStart();
         if (!mUnavailable) {
+            getActivity().registerReceiver(mReceiver,
+                    new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION));
             initPreferences();
         }
     }
 
+    @Override
+    public void onStop() {
+        super.onStop();
+        if (!mUnavailable) {
+            getActivity().unregisterReceiver(mReceiver);
+        }
+    }
+
     private void initPreferences() {
         final Context context = getActivity();
         Intent intent = new Intent(Credentials.INSTALL_AS_USER_ACTION);
@@ -90,11 +110,13 @@
         Preference pref = findPreference(KEY_INSTALL_CREDENTIALS);
         pref.setIntent(intent);
 
-
+        final WifiManager wifiManager =
+                (WifiManager)getActivity().getSystemService(Context.WIFI_SERVICE);
         Intent wifiDirectIntent = new Intent(context,
                 com.android.settings.Settings.WifiP2pSettingsActivity.class);
         Preference wifiDirectPref = findPreference(KEY_WIFI_DIRECT);
         wifiDirectPref.setIntent(wifiDirectIntent);
+        wifiDirectPref.setEnabled(wifiManager.isWifiEnabled());
 
         // WpsDialog: Create the dialog like WifiSettings does.
         Preference wpsPushPref = findPreference(KEY_WPS_PUSH);
@@ -105,6 +127,7 @@
                     return true;
                 }
         });
+        wpsPushPref.setEnabled(wifiManager.isWifiEnabled());
 
         // WpsDialog: Create the dialog like WifiSettings does.
         Preference wpsPinPref = findPreference(KEY_WPS_PIN);
@@ -115,6 +138,7 @@
                     return true;
                 }
         });
+        wpsPinPref.setEnabled(wifiManager.isWifiEnabled());
     }
 
     /* Wrapper class for the WPS dialog to properly handle life cycle events like rotation. */
diff --git a/tests/robotests/src/com/android/settings/accounts/AccountPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accounts/AccountPreferenceControllerTest.java
index 552c689..398e9c5 100644
--- a/tests/robotests/src/com/android/settings/accounts/AccountPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/AccountPreferenceControllerTest.java
@@ -190,6 +190,24 @@
     }
 
     @Test
+    @Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
+    public void onResume_noPreferenceScreen_shouldNotCrash() {
+        final List<UserInfo> infos = new ArrayList<>();
+        infos.add(new UserInfo(1, "user 1", 0));
+        when(mUserManager.isManagedProfile()).thenReturn(false);
+        when(mUserManager.isLinkedUser()).thenReturn(false);
+        when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
+
+        AccessiblePreferenceCategory preferenceGroup = mock(AccessiblePreferenceCategory.class);
+        when(mAccountHelper.createAccessiblePreferenceCategory(any(Context.class))).thenReturn(
+                preferenceGroup);
+
+        mController.onResume();
+
+        // Should not crash
+    }
+
+    @Test
     public void updateRawDataToIndex_ManagedProfile_shouldNotUpdate() {
         final List<SearchIndexableRaw> data = new ArrayList<>();
         when(mUserManager.isManagedProfile()).thenReturn(true);
diff --git a/tests/robotests/src/com/android/settings/search/DatabaseResultLoaderTest.java b/tests/robotests/src/com/android/settings/search/DatabaseResultLoaderTest.java
new file mode 100644
index 0000000..c592aef
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/search/DatabaseResultLoaderTest.java
@@ -0,0 +1,246 @@
+/*
+ * 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.search;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+import com.android.settings.search2.DatabaseIndexingUtils;
+import com.android.settings.search2.DatabaseResultLoader;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+import java.lang.reflect.Field;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class DatabaseResultLoaderTest {
+    private Context mContext;
+
+    private DatabaseResultLoader loader;
+
+    SQLiteDatabase mDb;
+
+    @Before
+    public void setUp() {
+        mContext = RuntimeEnvironment.application;
+        mDb = IndexDatabaseHelper.getInstance(mContext).getWritableDatabase();
+        setUpDb();
+    }
+
+    @After
+    public void cleanUp() {
+        Field instance;
+        Class clazz = IndexDatabaseHelper.class;
+        try {
+            instance = clazz.getDeclaredField("sSingleton");
+            instance.setAccessible(true);
+            instance.set(null, null);
+        } catch (Exception e) {
+            throw new RuntimeException();
+        }
+    }
+
+    @Test
+    public void testMatchTitle() {
+        loader = new DatabaseResultLoader(mContext, "title");
+        assertThat(loader.loadInBackground().size()).isEqualTo(3);
+    }
+
+    @Test
+    public void testMatchSummary() {
+        loader = new DatabaseResultLoader(mContext, "summary");
+        assertThat(loader.loadInBackground().size()).isEqualTo(3);
+    }
+
+    @Test
+    public void testMatchKeywords() {
+        loader = new DatabaseResultLoader(mContext, "keywords");
+        assertThat(loader.loadInBackground().size()).isEqualTo(3);
+    }
+
+    @Test
+    public void testMatchEntries() {
+        loader = new DatabaseResultLoader(mContext, "entries");
+        assertThat(loader.loadInBackground().size()).isEqualTo(3);
+    }
+
+    @Test
+    public void testSpecialCaseWord_MatchesNonPrefix() {
+        insertSpecialCase("Data usage");
+        loader = new DatabaseResultLoader(mContext, "usage");
+        assertThat(loader.loadInBackground().size()).isEqualTo(1);
+    }
+
+    @Test
+    public void testSpecialCaseSpace_Matches() {
+        insertSpecialCase("space");
+        loader = new DatabaseResultLoader(mContext, " space ");
+        assertThat(loader.loadInBackground().size()).isEqualTo(1);
+    }
+
+    @Test
+    public void testSpecialCaseDash_MatchesWordNoDash() {
+        insertSpecialCase("wi-fi calling");
+        loader = new DatabaseResultLoader(mContext, "wifi");
+        assertThat(loader.loadInBackground().size()).isEqualTo(1);
+    }
+
+    @Test
+    public void testSpecialCaseDash_MatchesWordWithDash() {
+        insertSpecialCase("priorités seulment");
+        loader = new DatabaseResultLoader(mContext, "priorités");
+        assertThat(loader.loadInBackground().size()).isEqualTo(1);
+    }
+
+    @Test
+    public void testSpecialCaseDash_MatchesWordWithoutDash() {
+        insertSpecialCase("priorités seulment");
+        loader = new DatabaseResultLoader(mContext, "priorites");
+        assertThat(loader.loadInBackground().size()).isEqualTo(1);
+    }
+
+    @Test
+    public void testSpecialCaseDash_MatchesEntireQueryWithoutDash() {
+        insertSpecialCase("wi-fi calling");
+        loader = new DatabaseResultLoader(mContext, "wifi calling");
+        assertThat(loader.loadInBackground().size()).isEqualTo(1);
+    }
+
+    private void insertSpecialCase(String specialCase) {
+        String normalized = DatabaseIndexingUtils.normalizeHyphen(specialCase);
+        normalized = DatabaseIndexingUtils.normalizeString(normalized);
+
+        ContentValues values = new ContentValues();
+        values.put(IndexDatabaseHelper.IndexColumns.DOCID, 0);
+        values.put(IndexDatabaseHelper.IndexColumns.LOCALE, "en-us");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_RANK, 1);
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_TITLE, specialCase);
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_TITLE_NORMALIZED, normalized);
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_ON, "");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_ON_NORMALIZED, "");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_OFF, "");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_OFF_NORMALIZED, "");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_ENTRIES, "");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_KEYWORDS, "");
+        values.put(IndexDatabaseHelper.IndexColumns.CLASS_NAME,
+                "com.android.settings.gestures.GestureSettings");
+        values.put(IndexDatabaseHelper.IndexColumns.SCREEN_TITLE, "Moves");
+        values.put(IndexDatabaseHelper.IndexColumns.INTENT_ACTION, "");
+        values.put(IndexDatabaseHelper.IndexColumns.INTENT_TARGET_PACKAGE, "");
+        values.put(IndexDatabaseHelper.IndexColumns.INTENT_TARGET_CLASS, "");
+        values.put(IndexDatabaseHelper.IndexColumns.ICON, "");
+        values.put(IndexDatabaseHelper.IndexColumns.ENABLED, "");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_KEY_REF, "gesture_double_tap_power");
+        values.put(IndexDatabaseHelper.IndexColumns.USER_ID, 0);
+        values.put(IndexDatabaseHelper.IndexColumns.PAYLOAD_TYPE, 0);
+        values.put(IndexDatabaseHelper.IndexColumns.PAYLOAD, (String) null);
+
+        mDb.replaceOrThrow(IndexDatabaseHelper.Tables.TABLE_PREFS_INDEX, null, values);
+    }
+
+    private void setUpDb() {
+        ContentValues values = new ContentValues();
+        values.put(IndexDatabaseHelper.IndexColumns.DOCID, 0);
+        values.put(IndexDatabaseHelper.IndexColumns.LOCALE, "en-us");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_RANK, 1);
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_TITLE, "alpha_title");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_TITLE_NORMALIZED, "alpha title");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_ON, "alpha_summary");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_ON_NORMALIZED, "alpha_summary");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_OFF, "alpha_summary");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_OFF_NORMALIZED, "alpha_summary");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_ENTRIES, "alpha_entries");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_KEYWORDS, "alpha_keywords");
+        values.put(IndexDatabaseHelper.IndexColumns.CLASS_NAME,
+                "com.android.settings.gestures.GestureSettings");
+        values.put(IndexDatabaseHelper.IndexColumns.SCREEN_TITLE, "Moves");
+        values.put(IndexDatabaseHelper.IndexColumns.INTENT_ACTION, "");
+        values.put(IndexDatabaseHelper.IndexColumns.INTENT_TARGET_PACKAGE, "");
+        values.put(IndexDatabaseHelper.IndexColumns.INTENT_TARGET_CLASS, "");
+        values.put(IndexDatabaseHelper.IndexColumns.ICON, "");
+        values.put(IndexDatabaseHelper.IndexColumns.ENABLED, "");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_KEY_REF, "gesture_double_tap_power");
+        values.put(IndexDatabaseHelper.IndexColumns.USER_ID, 0);
+        values.put(IndexDatabaseHelper.IndexColumns.PAYLOAD_TYPE, 0);
+        values.put(IndexDatabaseHelper.IndexColumns.PAYLOAD, (String) null);
+
+        mDb.replaceOrThrow(IndexDatabaseHelper.Tables.TABLE_PREFS_INDEX, null, values);
+
+        values = new ContentValues();
+        values.put(IndexDatabaseHelper.IndexColumns.DOCID, 1);
+        values.put(IndexDatabaseHelper.IndexColumns.LOCALE, "en-us");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_RANK, 1);
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_TITLE, "bravo_title");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_TITLE_NORMALIZED, "bravo title");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_ON, "bravo_summary");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_ON_NORMALIZED, "bravo_summary");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_OFF, "bravo_summary");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_OFF_NORMALIZED, "bravo_summary");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_ENTRIES, "bravo_entries");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_KEYWORDS, "bravo_keywords");
+        values.put(IndexDatabaseHelper.IndexColumns.CLASS_NAME,
+                "com.android.settings.gestures.GestureSettings");
+        values.put(IndexDatabaseHelper.IndexColumns.SCREEN_TITLE, "Moves");
+        values.put(IndexDatabaseHelper.IndexColumns.INTENT_ACTION, "");
+        values.put(IndexDatabaseHelper.IndexColumns.INTENT_TARGET_PACKAGE, "");
+        values.put(IndexDatabaseHelper.IndexColumns.INTENT_TARGET_CLASS, "");
+        values.put(IndexDatabaseHelper.IndexColumns.ICON, "");
+        values.put(IndexDatabaseHelper.IndexColumns.ENABLED, "");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_KEY_REF, "gesture_double_tap_power");
+        values.put(IndexDatabaseHelper.IndexColumns.USER_ID, 0);
+        values.put(IndexDatabaseHelper.IndexColumns.PAYLOAD_TYPE, 0);
+        values.put(IndexDatabaseHelper.IndexColumns.PAYLOAD, (String) null);
+        mDb.replaceOrThrow(IndexDatabaseHelper.Tables.TABLE_PREFS_INDEX, null, values);
+
+        values = new ContentValues();
+        values.put(IndexDatabaseHelper.IndexColumns.DOCID, 2);
+        values.put(IndexDatabaseHelper.IndexColumns.LOCALE, "en-us");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_RANK, 1);
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_TITLE, "charlie_title");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_TITLE_NORMALIZED, "charlie title");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_ON, "charlie_summary");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_ON_NORMALIZED, "charlie_summary");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_OFF, "charlie_summary");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_OFF_NORMALIZED, "charlie_summary");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_ENTRIES, "charlie_entries");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_KEYWORDS, "charlie_keywords");
+        values.put(IndexDatabaseHelper.IndexColumns.CLASS_NAME,
+                "com.android.settings.gestures.GestureSettings");
+        values.put(IndexDatabaseHelper.IndexColumns.SCREEN_TITLE, "Moves");
+        values.put(IndexDatabaseHelper.IndexColumns.INTENT_ACTION, "");
+        values.put(IndexDatabaseHelper.IndexColumns.INTENT_TARGET_PACKAGE, "");
+        values.put(IndexDatabaseHelper.IndexColumns.INTENT_TARGET_CLASS, "");
+        values.put(IndexDatabaseHelper.IndexColumns.ICON, "");
+        values.put(IndexDatabaseHelper.IndexColumns.ENABLED, "");
+        values.put(IndexDatabaseHelper.IndexColumns.DATA_KEY_REF, "gesture_double_tap_power");
+        values.put(IndexDatabaseHelper.IndexColumns.USER_ID, 0);
+        values.put(IndexDatabaseHelper.IndexColumns.PAYLOAD_TYPE, 0);
+        values.put(IndexDatabaseHelper.IndexColumns.PAYLOAD, (String) null);
+
+        mDb.replaceOrThrow(IndexDatabaseHelper.Tables.TABLE_PREFS_INDEX, null, values);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/search2/CursorToSearchResultConverterTest.java b/tests/robotests/src/com/android/settings/search2/CursorToSearchResultConverterTest.java
index 98b250d..1847d0e 100644
--- a/tests/robotests/src/com/android/settings/search2/CursorToSearchResultConverterTest.java
+++ b/tests/robotests/src/com/android/settings/search2/CursorToSearchResultConverterTest.java
@@ -40,6 +40,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import static com.android.settings.search.IndexDatabaseHelper.IndexColumns;
+
 import static com.google.common.truth.Truth.assertThat;
 
 @RunWith(SettingsRobolectricTestRunner.class)
@@ -48,16 +50,32 @@
 
     private CursorToSearchResultConverter mConverter;
 
-    private static final String[] COLUMNS = new String[]{"rank", "title", "summary_on",
-            "summary off", "entries", "keywords", "class name", "screen title", "icon",
-            "intent action", "target package", "target class", "enabled", "key",
-            "payload_type", "payload"};
+    private static final String[] COLUMNS = new String[]{
+            IndexColumns.DOCID,
+            IndexColumns.DATA_TITLE,
+            IndexColumns.DATA_SUMMARY_ON,
+            IndexColumns.DATA_SUMMARY_OFF,
+            IndexColumns.CLASS_NAME,
+            IndexColumns.SCREEN_TITLE,
+            IndexColumns.ICON,
+            IndexColumns.INTENT_ACTION,
+            IndexColumns.INTENT_TARGET_PACKAGE,
+            IndexColumns.INTENT_TARGET_CLASS,
+            IndexColumns.DATA_KEY_REF,
+            IndexColumns.PAYLOAD_TYPE,
+            IndexColumns.PAYLOAD
+    };
 
-    private static final String[] TITLES = new String[]{"title1", "title2", "title3"};
-    private static final String SUMMARY = "SUMMARY";
+    private static final String ID = "id";
+    private static final String[] TITLES = {"title1", "title2", "title3"};
+    private static final String SUMMARY = "summary";
+    private static final String QUERY = "query";
+    private final int BASE_RANK = 1;
     private static final int EXAMPLES = 3;
+
     private static final Intent mIntent = new Intent("com.android.settings");
     private static final int mIcon = R.drawable.ic_search_history;
+    private List<SearchResult> mResults;
 
     private Drawable mDrawable;
 
@@ -65,32 +83,33 @@
     public void setUp() {
         Context context = Robolectric.buildActivity(Activity.class).get();
         mDrawable = context.getDrawable(mIcon);
-        mConverter = new CursorToSearchResultConverter(context);
+        mResults = new ArrayList<>();
+        mConverter = new CursorToSearchResultConverter(context, QUERY);
     }
 
     @Test
     public void testParseNullResults_ReturnsNull() {
-        List<SearchResult> results = mConverter.convertCursor(null);
+        List<SearchResult> results = mConverter.convertCursor(null, BASE_RANK);
         assertThat(results).isNull();
     }
 
     @Test
     public void testParseCursor_NotNull() {
-        List<SearchResult> results = mConverter.convertCursor(getDummyCursor());
+        List<SearchResult> results = mConverter.convertCursor(getDummyCursor(), BASE_RANK);
         assertThat(results).isNotNull();
     }
 
     @Test
     public void testParseCursor_MatchesRank() {
-        List<SearchResult> results = mConverter.convertCursor(getDummyCursor());
+        List<SearchResult> results = mConverter.convertCursor(getDummyCursor(), BASE_RANK);
         for (int i = 0; i < EXAMPLES; i++) {
-            assertThat(results.get(i).rank).isEqualTo(i);
+            assertThat(results.get(i).rank).isEqualTo(BASE_RANK);
         }
     }
 
     @Test
     public void testParseCursor_MatchesTitle() {
-        List<SearchResult> results = mConverter.convertCursor(getDummyCursor());
+        List<SearchResult> results = mConverter.convertCursor(getDummyCursor(), BASE_RANK);
         for (int i = 0; i < EXAMPLES; i++) {
             assertThat(results.get(i).title).isEqualTo(TITLES[i]);
         }
@@ -98,7 +117,7 @@
 
     @Test
     public void testParseCursor_MatchesSummary() {
-        List<SearchResult> results = mConverter.convertCursor(getDummyCursor());
+        List<SearchResult> results = mConverter.convertCursor(getDummyCursor(), BASE_RANK);
         for (int i = 0; i < EXAMPLES; i++) {
             assertThat(results.get(i).summary).isEqualTo(SUMMARY);
         }
@@ -106,7 +125,7 @@
 
     @Test
     public void testParseCursor_MatchesIcon() {
-        List<SearchResult> results = mConverter.convertCursor(getDummyCursor());
+        List<SearchResult> results = mConverter.convertCursor(getDummyCursor(), BASE_RANK);
         for (int i = 0; i < EXAMPLES; i++) {
             Drawable resultDrawable = results.get(i).icon;
             assertThat(resultDrawable.toString()).isEqualTo(mDrawable.toString());
@@ -116,7 +135,7 @@
     @Test
     public void testParseCursor_NoIcon() {
         List<SearchResult> results = mConverter.convertCursor(
-                getDummyCursor(false /* hasIcon */));
+                getDummyCursor(false /* hasIcon */), BASE_RANK);
         for (int i = 0; i < EXAMPLES; i++) {
             Drawable resultDrawable = results.get(i).icon;
             assertThat(resultDrawable).isNull();
@@ -125,7 +144,7 @@
 
     @Test
     public void testParseCursor_MatchesPayloadType() {
-        List<SearchResult> results = mConverter.convertCursor(getDummyCursor());
+        List<SearchResult> results = mConverter.convertCursor(getDummyCursor(), BASE_RANK);
         ResultPayload payload;
         for (int i = 0; i < EXAMPLES; i++) {
             payload = results.get(i).payload;
@@ -138,24 +157,21 @@
         MatrixCursor cursor = new MatrixCursor(COLUMNS);
         final String BLANK = "";
         cursor.addRow(new Object[]{
-                0,       // rank
-                TITLES[0],
-                SUMMARY,
+                ID,      // Doc ID
+                TITLES[0], // Title
+                SUMMARY, // Summary on
                 SUMMARY, // summary off
-                BLANK,   // entries
-                BLANK,   // Keywords
                 GestureSettings.class.getName(),
                 BLANK,   // screen title
                 null,    // icon
                 BLANK,   // action
                 null,    // target package
                 BLANK,   // target class
-                BLANK,   // enabled
-                BLANK,   // key
+                BLANK,   // Key
                 0,       // Payload Type
                 null     // Payload
         });
-        List<SearchResult> results = mConverter.convertCursor(cursor);
+        List<SearchResult> results = mConverter.convertCursor(cursor, BASE_RANK);
         IntentPayload payload = (IntentPayload) results.get(0).payload;
         Intent intent = payload.intent;
         assertThat(intent.getComponent().getClassName()).isEqualTo(SubSettings.class.getName());
@@ -163,7 +179,7 @@
 
     @Test
     public void testParseCursor_MatchesIntentPayload() {
-        List<SearchResult> results = mConverter.convertCursor(getDummyCursor());
+        List<SearchResult> results = mConverter.convertCursor(getDummyCursor(), BASE_RANK);
         IntentPayload payload;
         for (int i = 0; i < EXAMPLES; i++) {
             payload = (IntentPayload) results.get(i).payload;
@@ -185,24 +201,21 @@
         final InlineSwitchPayload payload = new InlineSwitchPayload(uri, source, map);
 
         cursor.addRow(new Object[]{
-                0,       // rank
-                TITLES[0],
-                SUMMARY,
+                ID,      // Doc ID
+                TITLES[0], // Title
+                SUMMARY, // Summary on
                 SUMMARY, // summary off
-                BLANK,   // entries
-                BLANK,   // Keywords
                 GestureSettings.class.getName(),
                 BLANK,   // screen title
                 null,    // icon
                 BLANK,   // action
                 null,    // target package
                 BLANK,   // target class
-                BLANK,   // enabled
-                BLANK,   // key
+                BLANK,   // Key
                 type,    // Payload Type
                 ResultPayloadUtils.marshall(payload) // Payload
         });
-        List<SearchResult> results = mConverter.convertCursor(cursor);
+        List<SearchResult> results = mConverter.convertCursor(cursor, BASE_RANK);
         InlineSwitchPayload newPayload = (InlineSwitchPayload) results.get(0).payload;
 
         assertThat(newPayload.settingsUri).isEqualTo(uri);
@@ -222,22 +235,17 @@
 
         for (int i = 0; i < EXAMPLES; i++) {
             ArrayList<String> item = new ArrayList<>(COLUMNS.length);
-            item.add(Integer.toString(i));
-            item.add(TITLES[i]);
-            item.add(SUMMARY);
+            item.add(ID + i); // Doc ID
+            item.add(TITLES[i]); // Title
+            item.add(SUMMARY); // Summary on
             item.add(BLANK); // summary off
-            item.add(BLANK); // entries
-            item.add(BLANK); // keywords
             item.add(BLANK); // classname
             item.add(BLANK); // screen title
-            item.add(hasIcon ? Integer.toString(mIcon) : null);
-            item.add(mIntent.getAction());
+            item.add(hasIcon ? Integer.toString(mIcon) : null); // Icon
+            item.add(mIntent.getAction()); // Intent action
             item.add(BLANK); // target package
             item.add(BLANK); // target class
-            item.add(BLANK); // enabled
-            item.add(BLANK); // key
-                             // Note there is no user id. This is omitted because it is not being
-                             // queried. Should the queries change, so should this method.
+            item.add(BLANK); // Key
             item.add(Integer.toString(0));     // Payload Type
             item.add(null); // Payload
 
diff --git a/tests/robotests/src/com/android/settings/search2/InstalledAppResultLoaderTest.java b/tests/robotests/src/com/android/settings/search2/InstalledAppResultLoaderTest.java
index e3c2180..24aa94b 100644
--- a/tests/robotests/src/com/android/settings/search2/InstalledAppResultLoaderTest.java
+++ b/tests/robotests/src/com/android/settings/search2/InstalledAppResultLoaderTest.java
@@ -46,7 +46,6 @@
 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
 public class InstalledAppResultLoaderTest {
 
-
     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
     private Context mContext;
     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
diff --git a/tests/unit/src/com/android/settings/core/SettingsGatewayTest.java b/tests/unit/src/com/android/settings/core/SettingsGatewayTest.java
new file mode 100644
index 0000000..abce2c8
--- /dev/null
+++ b/tests/unit/src/com/android/settings/core/SettingsGatewayTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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.core;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+
+import com.android.settings.core.gateway.SettingsGateway;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+import static org.junit.Assert.assertFalse;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SettingsGatewayTest {
+
+    private static final String TAG = "SettingsGatewayTest";
+
+    @Test
+    public void allRestrictedActivityMustBeDefinedInManifest() {
+        final Context context = InstrumentationRegistry.getTargetContext();
+        final PackageManager packageManager = context.getPackageManager();
+        final String packageName = context.getPackageName();
+        for (String className : SettingsGateway.SETTINGS_FOR_RESTRICTED) {
+            final Intent intent = new Intent();
+            intent.setComponent(new ComponentName(packageName, className));
+            List<ResolveInfo> resolveInfos = packageManager.queryIntentActivities(intent,
+                    PackageManager.MATCH_DISABLED_COMPONENTS);
+            Log.d(TAG, packageName + "/" + className + "; resolveInfo size: "
+                    + resolveInfos.size());
+            assertFalse(className + " is not-defined in manifest", resolveInfos.isEmpty());
+        }
+    }
+}