[automerger skipped] Merge tm-qpr-dev-plus-aosp-without-vendor@9467136 am: 65e1bf24ac -s ours am: d9b575dab1 -s ours

am skip reason: Merged-In Ib41fa4321fe2bc084856880feaab147a541fa2ea with SHA-1 63a9e6071e is already in history

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/SettingsIntelligence/+/20954646

Change-Id: I43d125005fdfc8e1030c2f909591b0191ca89142
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/Android.bp b/Android.bp
index d019e75..40a799d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -33,6 +33,7 @@
         "androidx.preference_preference",
         "androidx.recyclerview_recyclerview",
         "androidx.legacy_legacy-preference-v14",
+        "SettingsLibActivityEmbedding",
     ],
     proto: {
         type: "nano",
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index d776e59..4d49922 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -49,7 +49,8 @@
         <activity
             android:name=".search.SearchActivity"
             android:exported="true"
-            android:theme="@style/Theme.Settings.NoActionBar">
+            android:theme="@style/Theme.Settings.NoActionBar"
+            android:windowSoftInputMode="adjustResize">
             <intent-filter priority="-1">
                 <action android:name="com.android.settings.action.SETTINGS_SEARCH" />
                 <action android:name="android.settings.APP_SEARCH_SETTINGS" />
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index db9af8b..a7a52b3 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -17,7 +17,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="applications_settings" msgid="3446736638853404682">"Інфармацыя пра праграму"</string>
+    <string name="applications_settings" msgid="3446736638853404682">"Звесткі аб праграме"</string>
     <string name="accessibility_settings_classname" msgid="973410590374198997">"com.android.settings.accessibility.AccessibilitySettings"</string>
     <string name="accessibility_settings" msgid="1488998032020612740">"Спецыяльныя магчымасці"</string>
     <string name="physical_keyboard_title" msgid="3955072245281785000">"Фізічная клавіятура"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index aa21ed9..07d6ab4 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -17,7 +17,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="applications_settings" msgid="3446736638853404682">"Sovelluksen tiedot"</string>
+    <string name="applications_settings" msgid="3446736638853404682">"Sovellustiedot"</string>
     <string name="accessibility_settings_classname" msgid="973410590374198997">"com.android.settings.accessibility.AccessibilitySettings"</string>
     <string name="accessibility_settings" msgid="1488998032020612740">"Esteettömyys"</string>
     <string name="physical_keyboard_title" msgid="3955072245281785000">"Fyysinen näppäimistö"</string>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index b209564..55c1bdc 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -20,7 +20,7 @@
     <string name="applications_settings" msgid="3446736638853404682">"ຂໍ້ມູນແອັບ"</string>
     <string name="accessibility_settings_classname" msgid="973410590374198997">"com.android.settings.accessibility.AccessibilitySettings"</string>
     <string name="accessibility_settings" msgid="1488998032020612740">"ການຊ່ວຍເຂົ້າເຖິງ"</string>
-    <string name="physical_keyboard_title" msgid="3955072245281785000">"ແປ້ນພິມແທ້"</string>
+    <string name="physical_keyboard_title" msgid="3955072245281785000">"ແປ້ນພິມພາຍນອກ"</string>
     <string name="add_virtual_keyboard" msgid="542703692821933851">"ຈັດການແປ້ນພິມ"</string>
     <string name="app_name_settings_intelligence" msgid="8701735500346011661">"ການແນະນຳການຕັ້ງຄ່າ"</string>
     <string name="search_clear_history" msgid="6232116698940067519">"ລຶບລ້າງປະຫວັດ"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 61f1404..ab0504c 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -21,8 +21,8 @@
     <string name="accessibility_settings_classname" msgid="973410590374198997">"com.android.settings.accessibility.AccessibilitySettings"</string>
     <string name="accessibility_settings" msgid="1488998032020612740">"Accesibilitate"</string>
     <string name="physical_keyboard_title" msgid="3955072245281785000">"Tastatură fizică"</string>
-    <string name="add_virtual_keyboard" msgid="542703692821933851">"Gestionați tastaturile"</string>
+    <string name="add_virtual_keyboard" msgid="542703692821933851">"Gestionează tastaturile"</string>
     <string name="app_name_settings_intelligence" msgid="8701735500346011661">"Sugestii de setări"</string>
-    <string name="search_clear_history" msgid="6232116698940067519">"Ștergeți istoricul"</string>
+    <string name="search_clear_history" msgid="6232116698940067519">"Șterge istoricul"</string>
     <string name="search_no_results" msgid="6855095945475439835">"Niciun rezultat"</string>
 </resources>
diff --git a/src/com/android/settings/intelligence/search/IntentSearchViewHolder.java b/src/com/android/settings/intelligence/search/IntentSearchViewHolder.java
index b643368..ee574aa 100644
--- a/src/com/android/settings/intelligence/search/IntentSearchViewHolder.java
+++ b/src/com/android/settings/intelligence/search/IntentSearchViewHolder.java
@@ -16,13 +16,16 @@
  */
 package com.android.settings.intelligence.search;
 
+import static com.android.settings.intelligence.search.indexing.DatabaseIndexingUtils.SEARCH_RESULT_TRAMPOLINE_ACTION;
+
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
-import androidx.annotation.VisibleForTesting;
 import android.util.Log;
 import android.view.View;
 
+import androidx.annotation.VisibleForTesting;
+
 import com.android.settings.intelligence.nano.SettingsIntelligenceLogProto;
 
 import java.util.List;
@@ -59,8 +62,11 @@
                 final Intent intent = result.payload.getIntent();
                 // Use app user id to support work profile use case.
                 if (result instanceof AppSearchResult) {
-                    AppSearchResult appResult = (AppSearchResult) result;
-                    fragment.getActivity().startActivity(intent);
+                    if (SEARCH_RESULT_TRAMPOLINE_ACTION.equals(intent.getAction())) {
+                        fragment.startActivityForResult(intent, REQUEST_CODE_NO_OP);
+                    } else {
+                        fragment.startActivity(intent);
+                    }
                 } else {
                     final PackageManager pm = fragment.getActivity().getPackageManager();
                     final List<ResolveInfo> info = pm.queryIntentActivities(intent, 0 /* flags */);
diff --git a/src/com/android/settings/intelligence/search/SearchFragment.java b/src/com/android/settings/intelligence/search/SearchFragment.java
index 97445ff..86b5b37 100644
--- a/src/com/android/settings/intelligence/search/SearchFragment.java
+++ b/src/com/android/settings/intelligence/search/SearchFragment.java
@@ -293,6 +293,7 @@
     }
 
     public void onSearchResultClicked(SearchViewHolder resultViewHolder, SearchResult result) {
+        hideKeyboard();
         logSearchResultClicked(resultViewHolder, result);
         mSearchFeatureProvider.searchResultClicked(getContext(), mQuery, result);
         mSavedQueryController.saveQuery(mQuery);
diff --git a/src/com/android/settings/intelligence/search/indexing/DatabaseIndexingManager.java b/src/com/android/settings/intelligence/search/indexing/DatabaseIndexingManager.java
index 32add54..146b730 100644
--- a/src/com/android/settings/intelligence/search/indexing/DatabaseIndexingManager.java
+++ b/src/com/android/settings/intelligence/search/indexing/DatabaseIndexingManager.java
@@ -16,13 +16,13 @@
 
 package com.android.settings.intelligence.search.indexing;
 
-import static com.android.settings.intelligence.search.query.DatabaseResultTask.SELECT_COLUMNS;
-import static com.android.settings.intelligence.search.indexing.IndexDatabaseHelper.IndexColumns.DATA_AUTHORITY;
-import static com.android.settings.intelligence.search.indexing.IndexDatabaseHelper.IndexColumns.DATA_PACKAGE;
+import static com.android.settings.intelligence.search.SearchFeatureProvider.DEBUG;
 import static com.android.settings.intelligence.search.indexing.IndexDatabaseHelper.IndexColumns.CLASS_NAME;
+import static com.android.settings.intelligence.search.indexing.IndexDatabaseHelper.IndexColumns.DATA_AUTHORITY;
 import static com.android.settings.intelligence.search.indexing.IndexDatabaseHelper.IndexColumns.DATA_ENTRIES;
 import static com.android.settings.intelligence.search.indexing.IndexDatabaseHelper.IndexColumns.DATA_KEYWORDS;
 import static com.android.settings.intelligence.search.indexing.IndexDatabaseHelper.IndexColumns.DATA_KEY_REF;
+import static com.android.settings.intelligence.search.indexing.IndexDatabaseHelper.IndexColumns.DATA_PACKAGE;
 import static com.android.settings.intelligence.search.indexing.IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_ON;
 import static com.android.settings.intelligence.search.indexing.IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_ON_NORMALIZED;
 import static com.android.settings.intelligence.search.indexing.IndexDatabaseHelper.IndexColumns.DATA_TITLE;
@@ -35,8 +35,9 @@
 import static com.android.settings.intelligence.search.indexing.IndexDatabaseHelper.IndexColumns.PAYLOAD;
 import static com.android.settings.intelligence.search.indexing.IndexDatabaseHelper.IndexColumns.PAYLOAD_TYPE;
 import static com.android.settings.intelligence.search.indexing.IndexDatabaseHelper.IndexColumns.SCREEN_TITLE;
+import static com.android.settings.intelligence.search.indexing.IndexDatabaseHelper.IndexColumns.TOP_LEVEL_MENU_KEY;
 import static com.android.settings.intelligence.search.indexing.IndexDatabaseHelper.Tables.TABLE_PREFS_INDEX;
-import static com.android.settings.intelligence.search.SearchFeatureProvider.DEBUG;
+import static com.android.settings.intelligence.search.query.DatabaseResultTask.SELECT_COLUMNS;
 
 import android.content.ContentValues;
 import android.content.Context;
@@ -47,13 +48,15 @@
 import android.database.sqlite.SQLiteException;
 import android.os.AsyncTask;
 import android.provider.SearchIndexablesContract;
-import androidx.annotation.VisibleForTesting;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Pair;
 
+import androidx.annotation.VisibleForTesting;
+
 import com.android.settings.intelligence.nano.SettingsIntelligenceLogProto;
 import com.android.settings.intelligence.overlay.FeatureFactory;
+import com.android.settings.intelligence.search.sitemap.HighlightableMenu;
 import com.android.settings.intelligence.search.sitemap.SiteMapPair;
 
 import java.util.List;
@@ -160,9 +163,21 @@
             database.beginTransaction();
 
             // Convert all Pre-index data to Index data and and insert to db.
-            final List<IndexData> indexData = getIndexData(preIndexData);
-            insertIndexData(database, indexData);
+            List<IndexData> indexData = getIndexData(preIndexData);
+
+            // Load SiteMap before writing index data into DB for updating payload
             insertSiteMapData(database, getSiteMapPairs(indexData, preIndexData.getSiteMapPairs()));
+            // Flag to re-init site map data in SiteMapManager.
+            FeatureFactory.get(mContext).searchFeatureProvider()
+                    .getSiteMapManager()
+                    .setInitialized(false);
+
+            // Update payload based on the site map to find the top menu entry
+            if (HighlightableMenu.isFeatureEnabled(mContext)) {
+                indexData = updateIndexDataPayload(mContext, indexData);
+            }
+
+            insertIndexData(database, indexData);
 
             // Only check for non-indexable key updates after initial index.
             // Enabled state with non-indexable keys is checked when items are first inserted.
@@ -178,7 +193,7 @@
 
     private List<IndexData> getIndexData(PreIndexData data) {
         if (mConverter == null) {
-            mConverter = getIndexDataConverter(mContext);
+            mConverter = getIndexDataConverter();
         }
         return mConverter.convertPreIndexDataToIndexData(data);
     }
@@ -186,7 +201,7 @@
     private List<SiteMapPair> getSiteMapPairs(List<IndexData> indexData,
             List<Pair<String, String>> siteMapClassNames) {
         if (mConverter == null) {
-            mConverter = getIndexDataConverter(mContext);
+            mConverter = getIndexDataConverter();
         }
         return mConverter.convertSiteMapPairs(indexData, siteMapClassNames);
     }
@@ -201,6 +216,13 @@
         }
     }
 
+    private List<IndexData> updateIndexDataPayload(Context context, List<IndexData> indexData) {
+        if (mConverter == null) {
+            mConverter = getIndexDataConverter();
+        }
+        return mConverter.updateIndexDataPayload(context, indexData);
+    }
+
     /**
      * Inserts all of the entries in {@param indexData} into the {@param database}
      * as Search Data and as part of the Information Hierarchy.
@@ -232,6 +254,7 @@
             values.put(DATA_KEY_REF, dataRow.key);
             values.put(PAYLOAD_TYPE, dataRow.payloadType);
             values.put(PAYLOAD, dataRow.payload);
+            values.put(TOP_LEVEL_MENU_KEY, dataRow.topLevelMenuKey);
 
             database.replaceOrThrow(TABLE_PREFS_INDEX, null, values);
         }
@@ -316,8 +339,13 @@
      * Protected method to get a new IndexDataConverter instance. This method can be overridden
      * in subclasses to substitute in a custom IndexDataConverter.
      */
+    protected IndexDataConverter getIndexDataConverter() {
+        return new IndexDataConverter();
+    }
+
+    @Deprecated
     protected IndexDataConverter getIndexDataConverter(Context context) {
-        return new IndexDataConverter(context);
+        return getIndexDataConverter();
     }
 
     public class IndexingTask extends AsyncTask<Void, Void, Void> {
@@ -355,4 +383,4 @@
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/com/android/settings/intelligence/search/indexing/DatabaseIndexingUtils.java b/src/com/android/settings/intelligence/search/indexing/DatabaseIndexingUtils.java
index 534a20c..c7afcd4 100644
--- a/src/com/android/settings/intelligence/search/indexing/DatabaseIndexingUtils.java
+++ b/src/com/android/settings/intelligence/search/indexing/DatabaseIndexingUtils.java
@@ -16,9 +16,13 @@
 
 package com.android.settings.intelligence.search.indexing;
 
+import static android.provider.Settings.EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_HIGHLIGHT_MENU_KEY;
+import static android.provider.Settings.EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI;
+
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.net.Uri;
 import android.text.TextUtils;
 
 /**
@@ -44,16 +48,51 @@
     public static final String SEARCH_RESULT_TRAMPOLINE_ACTION =
             "com.android.settings.SEARCH_RESULT_TRAMPOLINE";
 
+    // Additional extra of Settings#ACTION_SETTINGS_LARGE_SCREEN_DEEP_LINK.
+    // Set & get Uri of the Intent separately to prevent failure of Intent#ParseUri.
+    private static final String EXTRA_SETTINGS_LARGE_SCREEN_DEEP_LINK_INTENT_DATA =
+            "settings_large_screen_deep_link_intent_data";
+
     /**
      * Builds intent that launches the search destination as a sub-setting.
      */
-    public static Intent buildSearchTrampolineIntent(Context context, String className, String key,
-            String screenTitle) {
+    public static Intent buildSearchTrampolineIntent(String className, String key,
+            String screenTitle, String highlightMenuKey) {
         final Intent intent = new Intent(SEARCH_RESULT_TRAMPOLINE_ACTION);
         intent.putExtra(EXTRA_SHOW_FRAGMENT, className)
                 .putExtra(EXTRA_SHOW_FRAGMENT_TITLE, screenTitle)
                 .putExtra(EXTRA_SOURCE_METRICS_CATEGORY, DASHBOARD_SEARCH_RESULTS)
-                .putExtra(EXTRA_FRAGMENT_ARG_KEY, key);
+                .putExtra(EXTRA_FRAGMENT_ARG_KEY, key)
+                .putExtra(EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_HIGHLIGHT_MENU_KEY, highlightMenuKey);
+        return intent;
+    }
+
+    /**
+     *  Builds intent that launches the search destination as a deep link.
+     */
+    public static Intent buildSearchTrampolineIntent(String action, String targetPackage,
+            String targetClass, String key, String highlightMenuKey) {
+        final Intent intent = new Intent(SEARCH_RESULT_TRAMPOLINE_ACTION);
+        intent.putExtra(EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI,
+                        buildDirectSearchResultIntent(action, targetPackage, targetClass, key)
+                                .toUri(Intent.URI_INTENT_SCHEME))
+                .putExtra(EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_HIGHLIGHT_MENU_KEY, highlightMenuKey);
+        return intent;
+    }
+
+    /**
+     *  Builds intent that launches the search destination as a deep link.
+     */
+    public static Intent buildSearchTrampolineIntent(Intent targetIntent, String highlightMenuKey) {
+        // Relay target intent data to prevent future failure of Intent#ParseUri.
+        final Uri data = targetIntent.getData();
+        targetIntent = new Intent(targetIntent);
+        targetIntent.setData(null);
+        final Intent intent = new Intent(SEARCH_RESULT_TRAMPOLINE_ACTION);
+        intent.putExtra(EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI,
+                        targetIntent.toUri(Intent.URI_INTENT_SCHEME))
+                .putExtra(EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_HIGHLIGHT_MENU_KEY, highlightMenuKey)
+                .putExtra(EXTRA_SETTINGS_LARGE_SCREEN_DEEP_LINK_INTENT_DATA, data);
         return intent;
     }
 
@@ -64,6 +103,7 @@
             final ComponentName component = new ComponentName(targetPackage, targetClass);
             intent.setComponent(component);
         }
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         return intent;
     }
 
diff --git a/src/com/android/settings/intelligence/search/indexing/IndexData.java b/src/com/android/settings/intelligence/search/indexing/IndexData.java
index 7318eaa..75de062 100644
--- a/src/com/android/settings/intelligence/search/indexing/IndexData.java
+++ b/src/com/android/settings/intelligence/search/indexing/IndexData.java
@@ -57,7 +57,10 @@
     public final String key;
     public final int payloadType;
     public final byte[] payload;
+    public final String highlightableMenuKey; // the key of top level settings row
+    public final String topLevelMenuKey; // the key for highlighting the menu entry
 
+    private final Builder mBuilder;
     private static final String NON_BREAKING_HYPHEN = "\u2011";
     private static final String EMPTY = "";
     private static final String HYPHEN = "-";
@@ -96,6 +99,14 @@
         payloadType = builder.mPayloadType;
         payload = builder.mPayload != null ? ResultPayloadUtils.marshall(builder.mPayload)
                 : null;
+        highlightableMenuKey = builder.mHighlightableMenuKey;
+        topLevelMenuKey = builder.mTopLevelMenuKey;
+        mBuilder = builder;
+    }
+
+    /** Returns the builder of the IndexData. */
+    public Builder mutate() {
+        return mBuilder;
     }
 
     @Override
@@ -168,6 +179,8 @@
         @ResultPayload.PayloadType
         private int mPayloadType;
         private ResultPayload mPayload;
+        private String mHighlightableMenuKey;
+        private String mTopLevelMenuKey;
 
         @Override
         public String toString() {
@@ -277,6 +290,17 @@
             return this;
         }
 
+        public Builder setHighlightableMenuKey(String highlightableMenuKey) {
+            mHighlightableMenuKey = highlightableMenuKey;
+            return this;
+        }
+
+        Builder setTopLevelMenuKey(String topLevelMenuKey) {
+            mTopLevelMenuKey = topLevelMenuKey;
+            mPayload = null; // clear the payload to rebuild intent
+            return this;
+        }
+
         /**
          * Payload type is added when a Payload is added to the Builder in {setPayload}
          *
@@ -292,11 +316,11 @@
          * Adds intent to inline payloads, or creates an Intent Payload as a fallback if the
          * payload is null.
          */
-        private void setIntent(Context context) {
+        private void setIntent() {
             if (mPayload != null) {
                 return;
             }
-            final Intent intent = buildIntent(context);
+            final Intent intent = buildIntent();
             mPayload = new ResultPayload(intent);
             mPayloadType = ResultPayload.PayloadType.INTENT;
         }
@@ -305,25 +329,35 @@
          * Builds Intent payload for the builder.
          * This protected method that can be overridden in a subclass for custom intents.
          */
-        protected Intent buildIntent(Context context) {
+        protected Intent buildIntent() {
             final Intent intent;
 
             // TODO REFACTOR (b/62807132) With inline results re-add proper intent support
             boolean isEmptyIntentAction = TextUtils.isEmpty(mIntentAction);
             if (isEmptyIntentAction) {
                 // No intent action is set, or the intent action is for a sub-setting.
-                intent = DatabaseIndexingUtils.buildSearchTrampolineIntent(context, mClassName,
-                        mKey, mScreenTitle);
+                intent = DatabaseIndexingUtils.buildSearchTrampolineIntent(mClassName, mKey,
+                        mScreenTitle, mTopLevelMenuKey);
             } else {
-                intent = DatabaseIndexingUtils.buildDirectSearchResultIntent(mIntentAction,
-                        mIntentTargetPackage, mIntentTargetClass, mKey);
+                if (!TextUtils.isEmpty(mTopLevelMenuKey)) {
+                    intent = DatabaseIndexingUtils.buildSearchTrampolineIntent(mIntentAction,
+                            mIntentTargetPackage, mIntentTargetClass, mKey, mTopLevelMenuKey);
+                } else {
+                    intent = DatabaseIndexingUtils.buildDirectSearchResultIntent(mIntentAction,
+                            mIntentTargetPackage, mIntentTargetClass, mKey);
+                }
             }
             return intent;
         }
 
-        public IndexData build(Context context) {
-            setIntent(context);
+        @Deprecated
+        protected Intent buildIntent(Context context) {
+            return buildIntent();
+        }
+
+        public IndexData build() {
+            setIntent();
             return new IndexData(this);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/com/android/settings/intelligence/search/indexing/IndexDataConverter.java b/src/com/android/settings/intelligence/search/indexing/IndexDataConverter.java
index f57ce6b..670bb70 100644
--- a/src/com/android/settings/intelligence/search/indexing/IndexDataConverter.java
+++ b/src/com/android/settings/intelligence/search/indexing/IndexDataConverter.java
@@ -34,6 +34,8 @@
 import com.android.settings.intelligence.search.ResultPayload;
 import com.android.settings.intelligence.search.SearchFeatureProvider;
 import com.android.settings.intelligence.search.SearchIndexableRaw;
+import com.android.settings.intelligence.search.sitemap.HighlightableMenu;
+import com.android.settings.intelligence.search.sitemap.SiteMapManager;
 import com.android.settings.intelligence.search.sitemap.SiteMapPair;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -54,15 +56,17 @@
 
     private static final String TAG = "IndexDataConverter";
 
+    private static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
     private static final String NODE_NAME_PREFERENCE_SCREEN = "PreferenceScreen";
     private static final String NODE_NAME_CHECK_BOX_PREFERENCE = "CheckBoxPreference";
     private static final String NODE_NAME_LIST_PREFERENCE = "ListPreference";
     private static final List<String> SKIP_NODES = Arrays.asList("intent", "extra");
 
-    private final Context mContext;
+    public IndexDataConverter() {
+    }
 
+    @Deprecated
     public IndexDataConverter(Context context) {
-        mContext = context;
     }
 
     /**
@@ -86,7 +90,7 @@
                 if (data instanceof SearchIndexableRaw) {
                     final SearchIndexableRaw rawData = (SearchIndexableRaw) data;
                     final Set<String> rawNonIndexableKeys = nonIndexableKeys.get(authority);
-                    final IndexData convertedRaw = convertRaw(mContext, authority, rawData,
+                    final IndexData convertedRaw = convertRaw(authority, rawData,
                             rawNonIndexableKeys);
                     if (convertedRaw != null) {
                         indexData.add(convertedRaw);
@@ -130,7 +134,7 @@
             classToTitleMap.put(row.className, row.screenTitle);
             if (!TextUtils.isEmpty(row.childClassName)) {
                 pairs.add(new SiteMapPair(row.className, row.screenTitle,
-                        row.childClassName, row.updatedTitle));
+                        row.childClassName, row.updatedTitle, row.highlightableMenuKey));
             }
         }
         // Step 2: Extend the sitemap pairs by adding dynamic pairs provided by
@@ -143,20 +147,41 @@
                 Log.w(TAG, "Cannot build sitemap pair for incomplete names "
                         + pair + parentName + childName);
             } else {
-                pairs.add(new SiteMapPair(pair.first, parentName, pair.second, childName));
+                pairs.add(new SiteMapPair(pair.first, parentName, pair.second, childName,
+                        null /* highlightableMenuKey*/));
             }
         }
         // Done
         return pairs;
     }
 
+    public List<IndexData> updateIndexDataPayload(Context context, List<IndexData> indexData) {
+        final long startTime = System.currentTimeMillis();
+        final List<IndexData> updatedIndexData = new ArrayList<>(indexData);
+        for (IndexData row : indexData) {
+            String menuKey = row.highlightableMenuKey;
+            if (!TextUtils.isEmpty(menuKey)) {
+                // top level settings
+                continue;
+            }
+            menuKey = HighlightableMenu.getMenuKey(context, row);
+            if (TextUtils.isEmpty(menuKey)) {
+                continue;
+            }
+            updatedIndexData.remove(row);
+            updatedIndexData.add(row.mutate().setTopLevelMenuKey(menuKey).build());
+        }
+        Log.d(TAG, "Updating index data payload took: " + (System.currentTimeMillis() - startTime));
+        return updatedIndexData;
+    }
+
     /**
      * Return the conversion of {@link SearchIndexableRaw} to {@link IndexData}.
      * The fields of {@link SearchIndexableRaw} are a subset of {@link IndexData},
      * and there is some data sanitization in the conversion.
      */
     @Nullable
-    private IndexData convertRaw(Context context, String authority, SearchIndexableRaw raw,
+    private IndexData convertRaw(String authority, SearchIndexableRaw raw,
             Set<String> nonIndexableKeys) {
         if (TextUtils.isEmpty(raw.key)) {
             Log.w(TAG, "Skipping null key for raw indexable " + authority + "/" + raw.title);
@@ -181,7 +206,7 @@
                 .setAuthority(authority)
                 .setKey(raw.key);
 
-        return builder.build(context);
+        return builder.build();
     }
 
     /**
@@ -227,6 +252,7 @@
             String keywords;
             String headerKeywords;
             String childFragment;
+            String highlightableMenuKey = null;
             @DrawableRes int iconResId;
             ResultPayload payload;
             boolean enabled;
@@ -281,6 +307,11 @@
                 enabled = !nonIndexableKeys.contains(key);
                 keywords = XmlParserUtils.getDataKeywords(context, attrs);
                 iconResId = XmlParserUtils.getDataIcon(context, attrs);
+                if (TextUtils.equals(sir.packageName, SETTINGS_PACKAGE_NAME)
+                        && SiteMapManager.isTopLevelSettings(sir.className)) {
+                    highlightableMenuKey = XmlParserUtils.getHighlightableMenuKey(context, attrs);
+                }
+
 
                 if (isHeaderUnique && TextUtils.equals(headerTitle, title)) {
                     isHeaderUnique = false;
@@ -298,6 +329,8 @@
                         .setIntentTargetPackage(sir.intentTargetPackage)
                         .setIntentTargetClass(sir.intentTargetClass)
                         .setEnabled(enabled)
+                        .setHighlightableMenuKey(highlightableMenuKey)
+                        .setTopLevelMenuKey(highlightableMenuKey)
                         .setKey(key);
 
                 if (!nodeName.equals(NODE_NAME_CHECK_BOX_PREFERENCE)) {
@@ -354,7 +387,7 @@
 
     private void tryAddIndexDataToList(List<IndexData> list, IndexData.Builder data) {
         if (!TextUtils.isEmpty(data.getKey())) {
-            list.add(data.build(mContext));
+            list.add(data.build());
         } else {
             Log.w(TAG, "Skipping index for null-key item " + data);
         }
diff --git a/src/com/android/settings/intelligence/search/indexing/IndexDatabaseHelper.java b/src/com/android/settings/intelligence/search/indexing/IndexDatabaseHelper.java
index b9211e7..cd61350 100644
--- a/src/com/android/settings/intelligence/search/indexing/IndexDatabaseHelper.java
+++ b/src/com/android/settings/intelligence/search/indexing/IndexDatabaseHelper.java
@@ -40,7 +40,7 @@
     private static final String TAG = "IndexDatabaseHelper";
 
     private static final String DATABASE_NAME = "search_index.db";
-    private static final int DATABASE_VERSION = 120;
+    private static final int DATABASE_VERSION = 121;
 
     @VisibleForTesting
     static final String SHARED_PREFS_TAG = "indexing_manager";
@@ -75,6 +75,7 @@
         String DATA_KEY_REF = "data_key_reference";
         String PAYLOAD_TYPE = "payload_type";
         String PAYLOAD = "payload";
+        String TOP_LEVEL_MENU_KEY = "top_level_menu_key";
     }
 
     public interface MetaColumns {
@@ -92,6 +93,7 @@
         String CHILD_CLASS = "child_class";
         String PARENT_TITLE = "parent_title";
         String CHILD_TITLE = "child_title";
+        String HIGHLIGHTABLE_MENU_KEY = "highlightable_menu_key";
     }
 
     private static final String CREATE_INDEX_TABLE =
@@ -136,6 +138,8 @@
                     IndexColumns.PAYLOAD_TYPE +
                     ", " +
                     IndexColumns.PAYLOAD +
+                    ", " +
+                    IndexColumns.TOP_LEVEL_MENU_KEY +
                     ");";
 
     private static final String CREATE_META_TABLE =
@@ -162,6 +166,8 @@
                     SiteMapColumns.PARENT_TITLE +
                     ", " +
                     SiteMapColumns.CHILD_TITLE +
+                    ", " +
+                    SiteMapColumns.HIGHLIGHTABLE_MENU_KEY +
                     ")";
     private static final String INSERT_BUILD_VERSION =
             "INSERT INTO " + Tables.TABLE_META_INDEX +
diff --git a/src/com/android/settings/intelligence/search/indexing/XmlParserUtils.java b/src/com/android/settings/intelligence/search/indexing/XmlParserUtils.java
index 4efbde1..d3e5c25 100644
--- a/src/com/android/settings/intelligence/search/indexing/XmlParserUtils.java
+++ b/src/com/android/settings/intelligence/search/indexing/XmlParserUtils.java
@@ -76,25 +76,7 @@
         if (TextUtils.isEmpty(keywordRes)) {
             return null;
         }
-        // The format of keyword is either a string, or @ followed by int (@123456).
-        // When it's int, we need to look up the actual string from context.
-        if (!keywordRes.startsWith("@")) {
-            // It's a string.
-            return keywordRes;
-        } else {
-            // It's a resource
-            try  {
-                final int resValue = Integer.parseInt(keywordRes.substring(1));
-                if (DevicePolicyResourcesUtils.isDevicePolicyResource(context, resValue)) {
-                    return DevicePolicyResourcesUtils.getDevicePolicyResource(context, resValue);
-                } else {
-                    return context.getString(resValue);
-                }
-            } catch (NumberFormatException e) {
-                Log.w(TAG, "Failed to parse keyword attribute, skipping " + keywordRes);
-                return null;
-            }
-        }
+        return getString(context, keywordRes);
     }
 
     public static int getDataIcon(Context context, AttributeSet attrs) {
@@ -112,6 +94,17 @@
                 R.styleable.Preference_android_fragment);
     }
 
+    /**
+     *  Returns if the attrs contains highlightableMenuKey="" element.
+     */
+    public static String getHighlightableMenuKey(Context context, AttributeSet attrs) {
+        String menuKey = attrs.getAttributeValue(NS_APP_RES_AUTO, "highlightableMenuKey");
+        if (!TextUtils.isEmpty(menuKey)) {
+            menuKey = getString(context, menuKey);
+        }
+        return menuKey;
+    }
+
     @Nullable
     private static String getData(Context context, AttributeSet set, int[] attrs, int resId) {
         final TypedArray ta = context.obtainStyledAttributes(set, attrs);
@@ -125,7 +118,6 @@
         return data;
     }
 
-
     private static String getDataEntries(Context context, AttributeSet set, int[] attrs,
             int resId) {
         final TypedArray sa = context.obtainStyledAttributes(set, attrs);
@@ -148,4 +140,26 @@
         }
         return result.toString();
     }
+
+    private static String getString(Context context, String res) {
+        // The format of the resource is either a string, or @ followed by int (@123456).
+        // When it's int, we need to look up the actual string from context.
+        if (!res.startsWith("@")) {
+            // It's a string.
+            return res;
+        } else {
+            // It's a resource
+            try {
+                final int resValue = Integer.parseInt(res.substring(1));
+                if (DevicePolicyResourcesUtils.isDevicePolicyResource(context, resValue)) {
+                    return DevicePolicyResourcesUtils.getDevicePolicyResource(context, resValue);
+                } else {
+                    return context.getString(resValue);
+                }
+            } catch (NumberFormatException e) {
+                Log.w(TAG, "Failed to parse keyword attribute, skipping " + res);
+                return null;
+            }
+        }
+    }
 }
diff --git a/src/com/android/settings/intelligence/search/query/AccessibilityServiceResultTask.java b/src/com/android/settings/intelligence/search/query/AccessibilityServiceResultTask.java
index d6de496..05d0a54 100644
--- a/src/com/android/settings/intelligence/search/query/AccessibilityServiceResultTask.java
+++ b/src/com/android/settings/intelligence/search/query/AccessibilityServiceResultTask.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.intelligence.search.query;
 
+import static com.android.settings.intelligence.search.sitemap.HighlightableMenu.MENU_KEY_ACCESSIBILITY;
+
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.content.ComponentName;
 import android.content.Context;
@@ -85,9 +87,9 @@
             final Drawable icon = serviceInfo.loadIcon(mPackageManager);
             final String componentName = new ComponentName(serviceInfo.packageName,
                     serviceInfo.name).flattenToString();
-            final Intent intent = DatabaseIndexingUtils.buildSearchTrampolineIntent(mContext,
+            final Intent intent = DatabaseIndexingUtils.buildSearchTrampolineIntent(
                     mContext.getString(R.string.accessibility_settings_classname),
-                    componentName, screenTitle);
+                    componentName, screenTitle, MENU_KEY_ACCESSIBILITY);
 
             results.add(new SearchResult.Builder()
                     .setTitle(title)
diff --git a/src/com/android/settings/intelligence/search/query/InputDeviceResultTask.java b/src/com/android/settings/intelligence/search/query/InputDeviceResultTask.java
index 4cad4cc..f4bd77d 100644
--- a/src/com/android/settings/intelligence/search/query/InputDeviceResultTask.java
+++ b/src/com/android/settings/intelligence/search/query/InputDeviceResultTask.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.intelligence.search.query;
 
+import static com.android.settings.intelligence.search.sitemap.HighlightableMenu.MENU_KEY_SYSTEM;
+
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -108,8 +110,8 @@
             if (wordDiff == NAME_NO_MATCH) {
                 continue;
             }
-            final Intent intent = DatabaseIndexingUtils.buildSearchTrampolineIntent(mContext,
-                    PHYSICAL_KEYBOARD_FRAGMENT, deviceName, screenTitle);
+            final Intent intent = DatabaseIndexingUtils.buildSearchTrampolineIntent(
+                    PHYSICAL_KEYBOARD_FRAGMENT, deviceName, screenTitle, MENU_KEY_SYSTEM);
             results.add(new SearchResult.Builder()
                     .setTitle(deviceName)
                     .setPayload(new ResultPayload(intent))
@@ -139,8 +141,8 @@
             final ServiceInfo serviceInfo = info.getServiceInfo();
             final String key = new ComponentName(serviceInfo.packageName, serviceInfo.name)
                     .flattenToString();
-            final Intent intent = DatabaseIndexingUtils.buildSearchTrampolineIntent(mContext,
-                    VIRTUAL_KEYBOARD_FRAGMENT, key, screenTitle);
+            final Intent intent = DatabaseIndexingUtils.buildSearchTrampolineIntent(
+                    VIRTUAL_KEYBOARD_FRAGMENT, key, screenTitle, MENU_KEY_SYSTEM);
             results.add(new SearchResult.Builder()
                     .setTitle(title)
                     .setSummary(summary)
diff --git a/src/com/android/settings/intelligence/search/query/InstalledAppResultTask.java b/src/com/android/settings/intelligence/search/query/InstalledAppResultTask.java
index 6732765..6d9060e 100644
--- a/src/com/android/settings/intelligence/search/query/InstalledAppResultTask.java
+++ b/src/com/android/settings/intelligence/search/query/InstalledAppResultTask.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.intelligence.search.query;
 
+import static com.android.settings.intelligence.search.sitemap.HighlightableMenu.MENU_KEY_APPS;
+
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
@@ -29,6 +31,7 @@
 import com.android.settings.intelligence.search.ResultPayload;
 import com.android.settings.intelligence.search.SearchResult;
 import com.android.settings.intelligence.search.indexing.DatabaseIndexingUtils;
+import com.android.settings.intelligence.search.sitemap.HighlightableMenu;
 import com.android.settings.intelligence.search.sitemap.SiteMapManager;
 
 import java.util.ArrayList;
@@ -40,11 +43,11 @@
  */
 public class InstalledAppResultTask extends SearchQueryTask.QueryWorker {
 
-    public static final int QUERY_WORKER_ID =
+    private static final int QUERY_WORKER_ID =
             SettingsIntelligenceLogProto.SettingsIntelligenceEvent.SEARCH_QUERY_INSTALLED_APPS;
+    private static final String INTENT_SCHEME = "package";
 
     private final PackageManager mPackageManager;
-    private final String INTENT_SCHEME = "package";
     private List<String> mBreadcrumb;
 
     public static SearchQueryTask newTask(Context context, SiteMapManager siteMapManager,
@@ -85,12 +88,14 @@
                 continue;
             }
 
-            final Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
+            final Intent targetIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
                     .setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
-                    .setData(
-                            Uri.fromParts(INTENT_SCHEME, info.packageName, null /* fragment */))
+                    .setData(Uri.fromParts(INTENT_SCHEME, info.packageName, null /* fragment */))
                     .putExtra(DatabaseIndexingUtils.EXTRA_SOURCE_METRICS_CATEGORY,
                             DatabaseIndexingUtils.DASHBOARD_SEARCH_RESULTS);
+            final Intent intent = HighlightableMenu.isFeatureEnabled(mContext)
+                    ? DatabaseIndexingUtils.buildSearchTrampolineIntent(targetIntent, MENU_KEY_APPS)
+                    : targetIntent;
 
             final AppSearchResult.Builder builder = new AppSearchResult.Builder();
             builder.setAppInfo(info)
diff --git a/src/com/android/settings/intelligence/search/sitemap/HighlightableMenu.java b/src/com/android/settings/intelligence/search/sitemap/HighlightableMenu.java
new file mode 100644
index 0000000..dc6a96a
--- /dev/null
+++ b/src/com/android/settings/intelligence/search/sitemap/HighlightableMenu.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2022 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.intelligence.search.sitemap;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.settings.intelligence.overlay.FeatureFactory;
+import com.android.settings.intelligence.search.indexing.IndexData;
+import com.android.settingslib.activityembedding.ActivityEmbeddingUtils;
+
+import java.util.Map;
+import java.util.Map.Entry;
+
+public class HighlightableMenu {
+
+    private static final String TAG = "HighlightableMenu";
+    private static final boolean DEBUG = false;
+
+    public static final String MENU_KEY_NETWORK = "top_level_network";
+    public static final String MENU_KEY_APPS = "top_level_apps";
+    public static final String MENU_KEY_ACCESSIBILITY = "top_level_accessibility";
+    public static final String MENU_KEY_PRIVACY = "top_level_privacy";
+    public static final String MENU_KEY_SYSTEM = "top_level_system";
+
+    private static final Map<String, String> sAuthorityToMenuKeyMap;
+    private static final Map<String, String> sPackageToMenuKeyMap;
+
+    static {
+        sAuthorityToMenuKeyMap = new ArrayMap<>();
+        sAuthorityToMenuKeyMap.put(
+                "com.android.permissioncontroller.role", MENU_KEY_APPS); // Default apps
+
+        sPackageToMenuKeyMap = new ArrayMap<>();
+        sPackageToMenuKeyMap.put(
+                "com.android.settings.network", MENU_KEY_NETWORK); // Settings Network page
+        sPackageToMenuKeyMap.put(
+                "com.android.permissioncontroller", MENU_KEY_PRIVACY); // Permission manager
+    }
+
+    private HighlightableMenu() {
+    }
+
+    public static boolean isFeatureEnabled(Context context) {
+        boolean enabled = ActivityEmbeddingUtils.isEmbeddingActivityEnabled(context);
+        Log.i(TAG, "isFeatureEnabled: " + enabled);
+        return enabled;
+    }
+
+    public static String getMenuKey(Context context, IndexData row) {
+        String menuKey;
+        SiteMapManager siteMap = FeatureFactory.get(context).searchFeatureProvider()
+                .getSiteMapManager();
+
+        // look up in SiteMap
+        SiteMapPair pair = siteMap.getTopLevelPair(context, row.className, row.screenTitle);
+        if (pair != null) {
+            menuKey = pair.getHighlightableMenuKey();
+            if (!TextUtils.isEmpty(menuKey)) {
+                return menuKey;
+            }
+        }
+
+        // look up in custom authority map
+        menuKey = sAuthorityToMenuKeyMap.get(row.authority);
+        if (!TextUtils.isEmpty(menuKey)) {
+            logD("Matched authority, title: " + row.updatedTitle + ", menuKey: " + menuKey);
+            return menuKey;
+        }
+
+        // look up in custom package map (package match)
+        menuKey = sPackageToMenuKeyMap.get(row.packageName);
+        if (!TextUtils.isEmpty(menuKey)) {
+            logD("Matched package, title: " + row.updatedTitle + ", menuKey: " + menuKey);
+            return menuKey;
+        }
+
+        // look up in custom package map (target package match)
+        menuKey = sPackageToMenuKeyMap.get(row.intentTargetPackage);
+        if (!TextUtils.isEmpty(menuKey)) {
+            logD("Matched target package, title: " + row.updatedTitle + ", menuKey: " + menuKey);
+            return menuKey;
+        }
+
+        // look up in custom package map (class prefix match)
+        if (!TextUtils.isEmpty(row.className)) {
+            for (Entry<String, String> entry : sPackageToMenuKeyMap.entrySet()) {
+                if (row.className.startsWith(entry.getKey())) {
+                    menuKey = entry.getValue();
+                    if (!TextUtils.isEmpty(menuKey)) {
+                        logD("Matched class prefix, title: " + row.updatedTitle
+                                + ", menuKey: " + menuKey);
+                        return menuKey;
+                    }
+                }
+            }
+        }
+
+        logD("Cannot get menu key for: " + row.updatedTitle
+                + ", data key: " + row.key
+                + ", top-level: " + (pair != null ? pair.getParentTitle() : row.screenTitle)
+                + ", package: " + row.packageName);
+        return menuKey;
+    }
+
+    private static void logD(String log) {
+        if (DEBUG) {
+            Log.d(TAG, log);
+        }
+    }
+}
diff --git a/src/com/android/settings/intelligence/search/sitemap/SiteMapManager.java b/src/com/android/settings/intelligence/search/sitemap/SiteMapManager.java
index 6575cab..a6e76b5 100644
--- a/src/com/android/settings/intelligence/search/sitemap/SiteMapManager.java
+++ b/src/com/android/settings/intelligence/search/sitemap/SiteMapManager.java
@@ -32,13 +32,16 @@
 public class SiteMapManager {
 
     private static final String TAG = "SiteMapManager";
+    private static final String TOP_LEVEL_SETTINGS
+            = "com.android.settings.homepage.TopLevelSettings";
     private static final boolean DEBUG_TIMING = false;
 
     public static final String[] SITE_MAP_COLUMNS = {
             SiteMapColumns.PARENT_CLASS,
             SiteMapColumns.PARENT_TITLE,
             SiteMapColumns.CHILD_CLASS,
-            SiteMapColumns.CHILD_TITLE
+            SiteMapColumns.CHILD_TITLE,
+            SiteMapColumns.HIGHLIGHTABLE_MENU_KEY
     };
 
     private final List<SiteMapPair> mPairs = new ArrayList<>();
@@ -46,6 +49,13 @@
     private boolean mInitialized;
 
     /**
+     * Check whether the specified class is top level settings class.
+     */
+    public static boolean isTopLevelSettings(String clazz) {
+        return TextUtils.equals(TOP_LEVEL_SETTINGS, clazz);
+    }
+
+    /**
      * Given a fragment class name and its screen title, build a breadcrumb from Settings root to
      * this screen.
      * <p/>
@@ -85,6 +95,48 @@
         }
     }
 
+    public synchronized SiteMapPair getTopLevelPair(Context context, String clazz,
+            String screenTitle) {
+        if (!mInitialized) {
+            init(context);
+        }
+
+        // find the default pair
+        SiteMapPair currentPair = null;
+        if (!TextUtils.isEmpty(clazz)) {
+            for (SiteMapPair pair : mPairs) {
+                if (TextUtils.equals(pair.getChildClass(), clazz)) {
+                    currentPair = pair;
+                    if (TextUtils.isEmpty(screenTitle)) {
+                        screenTitle = pair.getChildTitle();
+                    }
+                    break;
+                }
+            }
+        }
+
+        // recursively find the top level pair
+        String currentClass = clazz;
+        String currentTitle = screenTitle;
+        while (true) {
+            // look up parent by class and title
+            SiteMapPair pair = lookUpParent(currentClass, currentTitle);
+            if (pair == null) {
+                // fallback option: look up parent only by title
+                pair = lookUpParent(currentTitle);
+                if (pair == null) {
+                    return currentPair;
+                }
+            }
+            if (!TextUtils.isEmpty(pair.getHighlightableMenuKey())) {
+                return pair;
+            }
+            currentPair = pair;
+            currentClass = pair.getParentClass();
+            currentTitle = pair.getParentTitle();
+        }
+    }
+
     /**
      * Initialize a list of {@link SiteMapPair}s. Each pair knows about a single parent-child
      * page relationship.
@@ -95,6 +147,12 @@
             // Make sure only init once.
             return;
         }
+
+        // Will init again if site map table updated, need clear the old data if it's not empty.
+        if (!mPairs.isEmpty()) {
+            mPairs.clear();
+        }
+
         final long startTime = System.currentTimeMillis();
         // First load site map from static index table.
         final Context appContext = context.getApplicationContext();
@@ -106,7 +164,9 @@
                     sitemap.getString(sitemap.getColumnIndex(SiteMapColumns.PARENT_CLASS)),
                     sitemap.getString(sitemap.getColumnIndex(SiteMapColumns.PARENT_TITLE)),
                     sitemap.getString(sitemap.getColumnIndex(SiteMapColumns.CHILD_CLASS)),
-                    sitemap.getString(sitemap.getColumnIndex(SiteMapColumns.CHILD_TITLE)));
+                    sitemap.getString(sitemap.getColumnIndex(SiteMapColumns.CHILD_TITLE)),
+                    sitemap.getString(sitemap.getColumnIndex(SiteMapColumns.HIGHLIGHTABLE_MENU_KEY))
+            );
             mPairs.add(pair);
         }
         sitemap.close();
@@ -128,4 +188,21 @@
         return null;
     }
 
+    @WorkerThread
+    private SiteMapPair lookUpParent(String title) {
+        if (TextUtils.isEmpty(title)) {
+            return null;
+        }
+        for (SiteMapPair pair : mPairs) {
+            if (TextUtils.equals(title, pair.getChildTitle())) {
+                return pair;
+            }
+        }
+        return null;
+    }
+
+    @WorkerThread
+    public void setInitialized(boolean initialized) {
+        mInitialized = initialized;
+    }
 }
diff --git a/src/com/android/settings/intelligence/search/sitemap/SiteMapPair.java b/src/com/android/settings/intelligence/search/sitemap/SiteMapPair.java
index cf30dc4..a92f67b 100644
--- a/src/com/android/settings/intelligence/search/sitemap/SiteMapPair.java
+++ b/src/com/android/settings/intelligence/search/sitemap/SiteMapPair.java
@@ -33,13 +33,15 @@
     private final String mParentTitle;
     private final String mChildClass;
     private final String mChildTitle;
+    private final String mHighlightableMenuKey;
 
-    public SiteMapPair(String parentClass, String parentTitle, String childClass,
-            String childTitle) {
+    public SiteMapPair(String parentClass, String parentTitle, String childClass, String childTitle,
+            String highlightableMenuKey) {
         mParentClass = parentClass;
         mParentTitle = parentTitle;
         mChildClass = childClass;
         mChildTitle = childTitle;
+        mHighlightableMenuKey = highlightableMenuKey;
     }
 
     @Override
@@ -72,6 +74,10 @@
         return mChildTitle;
     }
 
+    public String getHighlightableMenuKey() {
+        return mHighlightableMenuKey;
+    }
+
     /**
      * Converts this object into {@link ContentValues}. The content follows schema in
      * {@link IndexDatabaseHelper.SiteMapColumns}.
@@ -83,6 +89,8 @@
         values.put(IndexDatabaseHelper.SiteMapColumns.PARENT_TITLE, mParentTitle);
         values.put(IndexDatabaseHelper.SiteMapColumns.CHILD_CLASS, mChildClass);
         values.put(IndexDatabaseHelper.SiteMapColumns.CHILD_TITLE, mChildTitle);
+        values.put(IndexDatabaseHelper.SiteMapColumns.HIGHLIGHTABLE_MENU_KEY,
+                mHighlightableMenuKey);
         return values;
     }
 }