diff --git a/src/com/android/settings/dashboard/SiteMapManager.java b/src/com/android/settings/dashboard/SiteMapManager.java index facd9edb3ac..50d7a1892da 100644 --- a/src/com/android/settings/dashboard/SiteMapManager.java +++ b/src/com/android/settings/dashboard/SiteMapManager.java @@ -16,23 +16,26 @@ package com.android.settings.dashboard; +import static android.provider.SearchIndexablesContract.SITE_MAP_COLUMNS; import static com.android.settings.dashboard.DashboardFragmentRegistry.CATEGORY_KEY_TO_PARENT_MAP; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; +import android.provider.SearchIndexablesContract.SiteMapColumns; import android.support.annotation.VisibleForTesting; import android.support.annotation.WorkerThread; import android.support.v4.util.ArrayMap; import android.text.TextUtils; import android.util.Log; + import com.android.settings.SettingsActivity; import com.android.settings.overlay.FeatureFactory; import com.android.settings.search.IndexDatabaseHelper; import com.android.settings.search.IndexDatabaseHelper.IndexColumns; -import com.android.settings.search.IndexDatabaseHelper.SiteMapColumns; import com.android.settingslib.drawer.DashboardCategory; import com.android.settingslib.drawer.Tile; + import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -47,14 +50,6 @@ public class SiteMapManager { private static final String TAG = "SiteMapManager"; private static final boolean DEBUG_TIMING = false; - @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) - public static final String[] SITE_MAP_COLUMNS = { - SiteMapColumns.PARENT_CLASS, - SiteMapColumns.PARENT_TITLE, - SiteMapColumns.CHILD_CLASS, - SiteMapColumns.CHILD_TITLE - }; - private static final String[] CLASS_TO_SCREEN_TITLE_COLUMNS = { IndexColumns.CLASS_NAME, IndexColumns.SCREEN_TITLE, @@ -108,7 +103,7 @@ public class SiteMapManager { * 2. IA: We know from {@link DashboardFeatureProvider} which page can be dynamically * injected to where. */ - @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + @VisibleForTesting @WorkerThread synchronized void init(Context context) { if (mInitialized) { diff --git a/src/com/android/settings/search/DatabaseIndexingManager.java b/src/com/android/settings/search/DatabaseIndexingManager.java index 970b50f4c60..0aeda6625d7 100644 --- a/src/com/android/settings/search/DatabaseIndexingManager.java +++ b/src/com/android/settings/search/DatabaseIndexingManager.java @@ -19,20 +19,18 @@ package com.android.settings.search; import static com.android.settings.search.CursorToSearchResultConverter.COLUMN_INDEX_ID; -import static com.android.settings.search.CursorToSearchResultConverter - .COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE; +import static com.android.settings.search.CursorToSearchResultConverter.COLUMN_INDEX_INTENT_ACTION_TARGET_PACKAGE; import static com.android.settings.search.CursorToSearchResultConverter.COLUMN_INDEX_KEY; import static com.android.settings.search.DatabaseResultLoader.SELECT_COLUMNS; -import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DOCID; import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.CLASS_NAME; import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_ENTRIES; import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_KEYWORDS; import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_KEY_REF; import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_ON; -import static com.android.settings.search.IndexDatabaseHelper.IndexColumns - .DATA_SUMMARY_ON_NORMALIZED; +import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_SUMMARY_ON_NORMALIZED; import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_TITLE; import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DATA_TITLE_NORMALIZED; +import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.DOCID; import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.ENABLED; import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.ICON; import static com.android.settings.search.IndexDatabaseHelper.IndexColumns.INTENT_ACTION; @@ -55,6 +53,7 @@ import android.database.sqlite.SQLiteException; import android.os.AsyncTask; import android.os.Build; import android.provider.SearchIndexablesContract; +import android.provider.SearchIndexablesContract.SiteMapColumns; import android.support.annotation.VisibleForTesting; import android.text.TextUtils; import android.util.Log; @@ -68,7 +67,6 @@ import com.android.settings.search.indexing.PreIndexDataCollector; import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.Objects; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; @@ -276,17 +274,11 @@ public class DatabaseIndexingManager { if (!TextUtils.isEmpty(dataRow.className) && !TextUtils.isEmpty(dataRow.childClassName)) { - ContentValues siteMapPair = new ContentValues(); - final int pairDocId = Objects.hash(dataRow.className, dataRow.childClassName); - siteMapPair.put(IndexDatabaseHelper.SiteMapColumns.DOCID, pairDocId); - siteMapPair.put(IndexDatabaseHelper.SiteMapColumns.PARENT_CLASS, - dataRow.className); - siteMapPair.put(IndexDatabaseHelper.SiteMapColumns.PARENT_TITLE, - dataRow.screenTitle); - siteMapPair.put(IndexDatabaseHelper.SiteMapColumns.CHILD_CLASS, - dataRow.childClassName); - siteMapPair.put(IndexDatabaseHelper.SiteMapColumns.CHILD_TITLE, - dataRow.updatedTitle); + final ContentValues siteMapPair = new ContentValues(); + siteMapPair.put(SiteMapColumns.PARENT_CLASS, dataRow.className); + siteMapPair.put(SiteMapColumns.PARENT_TITLE, dataRow.screenTitle); + siteMapPair.put(SiteMapColumns.CHILD_CLASS, dataRow.childClassName); + siteMapPair.put(SiteMapColumns.CHILD_TITLE, dataRow.updatedTitle); database.replaceOrThrow(IndexDatabaseHelper.Tables.TABLE_SITE_MAP, null /* nullColumnHack */, siteMapPair); diff --git a/src/com/android/settings/search/IndexDatabaseHelper.java b/src/com/android/settings/search/IndexDatabaseHelper.java index b85b6c017e7..19e34194a5a 100644 --- a/src/com/android/settings/search/IndexDatabaseHelper.java +++ b/src/com/android/settings/search/IndexDatabaseHelper.java @@ -22,6 +22,7 @@ import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.os.Build; +import android.provider.SearchIndexablesContract.SiteMapColumns; import android.support.annotation.VisibleForTesting; import android.text.TextUtils; import android.util.Log; @@ -33,7 +34,7 @@ public class IndexDatabaseHelper extends SQLiteOpenHelper { private static final String TAG = "IndexDatabaseHelper"; private static final String DATABASE_NAME = "search_index.db"; - private static final int DATABASE_VERSION = 117; + private static final int DATABASE_VERSION = 118; private static final String SHARED_PREFS_TAG = "indexing_manager"; @@ -80,14 +81,6 @@ public class IndexDatabaseHelper extends SQLiteOpenHelper { String TIME_STAMP = "timestamp"; } - public interface SiteMapColumns { - String DOCID = "docid"; - String PARENT_CLASS = "parent_class"; - String CHILD_CLASS = "child_class"; - String PARENT_TITLE = "parent_title"; - String CHILD_TITLE = "child_title"; - } - private static final String CREATE_INDEX_TABLE = "CREATE VIRTUAL TABLE " + Tables.TABLE_PREFS_INDEX + " USING fts4" + "(" + diff --git a/src/com/android/settings/search/SettingsSearchIndexablesProvider.java b/src/com/android/settings/search/SettingsSearchIndexablesProvider.java index 968847b9b27..9e350829dd7 100644 --- a/src/com/android/settings/search/SettingsSearchIndexablesProvider.java +++ b/src/com/android/settings/search/SettingsSearchIndexablesProvider.java @@ -40,16 +40,24 @@ import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_RES import static android.provider.SearchIndexablesContract.INDEXABLES_RAW_COLUMNS; import static android.provider.SearchIndexablesContract.INDEXABLES_XML_RES_COLUMNS; import static android.provider.SearchIndexablesContract.NON_INDEXABLES_KEYS_COLUMNS; +import static android.provider.SearchIndexablesContract.SITE_MAP_COLUMNS; +import static com.android.settings.dashboard.DashboardFragmentRegistry.CATEGORY_KEY_TO_PARENT_MAP; import android.content.Context; import android.database.Cursor; import android.database.MatrixCursor; import android.provider.SearchIndexableResource; +import android.provider.SearchIndexablesContract; import android.provider.SearchIndexablesProvider; import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; +import com.android.settings.SettingsActivity; +import com.android.settings.overlay.FeatureFactory; +import com.android.settingslib.drawer.DashboardCategory; +import com.android.settingslib.drawer.Tile; + import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -134,6 +142,38 @@ public class SettingsSearchIndexablesProvider extends SearchIndexablesProvider { return cursor; } + @Override + public Cursor querySiteMapPairs() { + final MatrixCursor cursor = new MatrixCursor(SITE_MAP_COLUMNS); + final Context context = getContext(); + // Loop through all IA categories and pages and build additional SiteMapPairs + final List categories = FeatureFactory.getFactory(context) + .getDashboardFeatureProvider(context).getAllCategories(); + for (DashboardCategory category : categories) { + // Use the category key to look up parent (which page hosts this key) + final String parentClass = CATEGORY_KEY_TO_PARENT_MAP.get(category.key); + if (parentClass == null) { + continue; + } + // Build parent-child class pairs for all children listed under this key. + for (Tile tile : category.tiles) { + String childClass = null; + if (tile.metaData != null) { + childClass = tile.metaData.getString( + SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS); + } + if (childClass == null) { + continue; + } + cursor.newRow() + .add(SearchIndexablesContract.SiteMapColumns.PARENT_CLASS, parentClass) + .add(SearchIndexablesContract.SiteMapColumns.CHILD_CLASS, childClass); + } + } + // Done. + return cursor; + } + private List getNonIndexableKeysFromProvider(Context context) { final Collection values = SearchIndexableResources.providerValues(); final List nonIndexableKeys = new ArrayList<>(); diff --git a/tests/robotests/src/com/android/settings/search/SiteMapManagerTest.java b/tests/robotests/src/com/android/settings/search/SiteMapManagerTest.java deleted file mode 100644 index b441b66dc41..00000000000 --- a/tests/robotests/src/com/android/settings/search/SiteMapManagerTest.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * 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 android.os.Bundle; - -import com.android.settings.SettingsActivity; -import com.android.settings.testutils.SettingsRobolectricTestRunner; -import com.android.settings.TestConfig; -import com.android.settings.dashboard.SiteMapManager; -import com.android.settings.search.IndexDatabaseHelper.SiteMapColumns; -import com.android.settings.system.SystemDashboardFragment; -import com.android.settings.testutils.DatabaseTestUtils; -import com.android.settings.testutils.FakeFeatureFactory; -import com.android.settingslib.drawer.CategoryKey; -import com.android.settingslib.drawer.DashboardCategory; -import com.android.settingslib.drawer.Tile; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Answers; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; - -import java.util.Arrays; -import java.util.List; - -import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Mockito.when; - -@RunWith(SettingsRobolectricTestRunner.class) -@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) -public class SiteMapManagerTest { - - private static final int STATIC_DB_DEPTH = 4; - private static final String CLASS_PREFIX = "class_"; - private static final String TITLE_PREFIX = "title_"; - - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - private Context mMockContext; - private Context mContext; - private SQLiteDatabase mDb; - private SiteMapManager mSiteMapManager; - private FakeFeatureFactory mFeatureFactory; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - FakeFeatureFactory.setupForTest(mMockContext); - mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mMockContext); - - mContext = RuntimeEnvironment.application; - mDb = IndexDatabaseHelper.getInstance(mContext).getWritableDatabase(); - buildDb(); - mSiteMapManager = new SiteMapManager(); - } - - @After - public void cleanUp() { - DatabaseTestUtils.clearDb(mContext); - } - - @Test - public void buildBreadCrumb_onlyFromSiteMapDb_breadcrumbShouldLinkUp() { - List breadcrumb = mSiteMapManager.buildBreadCrumb(mContext, - CLASS_PREFIX + 0, TITLE_PREFIX + 0); - assertThat(breadcrumb.size()).isEqualTo(STATIC_DB_DEPTH + 1); - for (int i = 0; i < STATIC_DB_DEPTH; i++) { - assertThat(breadcrumb.get(i)).isEqualTo(TITLE_PREFIX + (STATIC_DB_DEPTH - i)); - } - } - - @Test - public void buildBreadCrumb_fromSiteMapDbAndDashboardProvider_breadcrumbShouldLinkUp() { - final String iaClass = SystemDashboardFragment.class.getName(); - final String iaTitle = "ia_title"; - - ContentValues index = new ContentValues(); - index.put(IndexDatabaseHelper.IndexColumns.CLASS_NAME, iaClass); - index.put(IndexDatabaseHelper.IndexColumns.SCREEN_TITLE, iaTitle); - mDb.replaceOrThrow(IndexDatabaseHelper.Tables.TABLE_PREFS_INDEX, null, index); - - final DashboardCategory category = new DashboardCategory(); - category.key = CategoryKey.CATEGORY_SYSTEM; - category.tiles.add(new Tile()); - category.tiles.get(0).title = TITLE_PREFIX + STATIC_DB_DEPTH; - category.tiles.get(0).metaData = new Bundle(); - category.tiles.get(0).metaData.putString(SettingsActivity.META_DATA_KEY_FRAGMENT_CLASS, - CLASS_PREFIX + STATIC_DB_DEPTH); - when(mFeatureFactory.dashboardFeatureProvider.getAllCategories()) - .thenReturn(Arrays.asList(category)); - - final List breadcrumb = mSiteMapManager.buildBreadCrumb(mContext, - CLASS_PREFIX + 0, TITLE_PREFIX + 0); - - assertThat(breadcrumb.size()).isEqualTo(STATIC_DB_DEPTH + 2); - assertThat(breadcrumb.get(0)) - .isEqualTo(iaTitle); - } - - @Test - public void buildBreadCrumb_classNotIndexed_shouldNotHaveBreadCrumb() { - final String title = "wrong_title"; - - final List breadcrumb = mSiteMapManager.buildBreadCrumb(mContext, - "wrong_class", title); - - assertThat(breadcrumb.size()).isEqualTo(1); - assertThat(breadcrumb.get(0)).isEqualTo(title); - } - - private void buildDb() { - for (int i = 0; i < STATIC_DB_DEPTH; i++) { - final ContentValues siteMapPair = new ContentValues(); - siteMapPair.put(SiteMapColumns.DOCID, i); - siteMapPair.put(SiteMapColumns.PARENT_CLASS, CLASS_PREFIX + (i + 1)); - siteMapPair.put(SiteMapColumns.PARENT_TITLE, TITLE_PREFIX + (i + 1)); - siteMapPair.put(SiteMapColumns.CHILD_CLASS, CLASS_PREFIX + i); - siteMapPair.put(SiteMapColumns.CHILD_TITLE, TITLE_PREFIX + i); - mDb.replaceOrThrow(IndexDatabaseHelper.Tables.TABLE_SITE_MAP, null, siteMapPair); - } - } -} diff --git a/tests/unit/src/com/android/settings/search/SettingsSearchIndexablesProviderTest.java b/tests/unit/src/com/android/settings/search/SettingsSearchIndexablesProviderTest.java new file mode 100644 index 00000000000..aed94a0ea67 --- /dev/null +++ b/tests/unit/src/com/android/settings/search/SettingsSearchIndexablesProviderTest.java @@ -0,0 +1,62 @@ +/* + * 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 static com.google.common.truth.Truth.assertThat; + +import android.content.Context; +import android.database.Cursor; +import android.net.Uri; +import android.provider.SearchIndexablesContract; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class SettingsSearchIndexablesProviderTest { + + private Context mContext; + + + @Before + public void setUp() { + mContext = InstrumentationRegistry.getTargetContext(); + } + + @Test + public void testSiteMapPairsFetched() { + final Uri uri = Uri.parse("content://" + mContext.getPackageName() + "/" + + SearchIndexablesContract.SITE_MAP_PAIRS_PATH); + final Cursor cursor = mContext.getContentResolver().query(uri, null, null, null, null); + + final int size = cursor.getCount(); + assertThat(size).isGreaterThan(0); + while (cursor.moveToNext()) { + assertThat(cursor.getString(cursor.getColumnIndexOrThrow( + SearchIndexablesContract.SiteMapColumns.PARENT_CLASS))) + .isNotEmpty(); + assertThat(cursor.getString(cursor.getColumnIndexOrThrow( + SearchIndexablesContract.SiteMapColumns.CHILD_CLASS))) + .isNotEmpty(); + } + } +}