From 5035f8c5590a8eea7bf372a325a4aa0ee1e96149 Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Wed, 2 Aug 2017 17:32:43 -0700 Subject: [PATCH] Move a11y indexing from DynamicContentMonitor to loader This is necessary to kill DynamicContentMonitor later - Removed all logic related to indexing accesiblitysetting from the monitor class and AccessibilitySetting page itself - Created a loader to search against A11yServices at runtime I noticed adding a loader in SearchResultsAdapter is rather manual. It's something we should consider refactor in the future. Bug: 64310452 Test: robotests Change-Id: Iff31aff65ce000991229433f294e2ec69af99da2 --- .../accessibility/AccessibilitySettings.java | 36 ----- .../AccessibilityServiceResultLoader.java | 123 ++++++++++++++++++ .../DynamicIndexableContentMonitor.java | 74 ----------- .../search/InstalledAppResultLoader.java | 3 +- .../search/SearchFeatureProvider.java | 14 +- .../search/SearchFeatureProviderImpl.java | 7 + .../settings/search/SearchFragment.java | 16 ++- .../settings/search/SearchResultsAdapter.java | 21 ++- .../AccessibilityServiceResultLoaderTest.java | 114 ++++++++++++++++ .../DynamicIndexableContentMonitorTest.java | 90 ++----------- .../search/InstalledAppResultLoaderTest.java | 34 ++--- .../search/MockAccessiblityLoader.java | 39 ++++++ .../settings/search/SearchFragmentTest.java | 17 +++ 13 files changed, 375 insertions(+), 213 deletions(-) create mode 100644 src/com/android/settings/search/AccessibilityServiceResultLoader.java create mode 100644 tests/robotests/src/com/android/settings/search/AccessibilityServiceResultLoaderTest.java create mode 100644 tests/robotests/src/com/android/settings/search/MockAccessiblityLoader.java diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java index afb3c3a832e..51b676df551 100644 --- a/src/com/android/settings/accessibility/AccessibilitySettings.java +++ b/src/com/android/settings/accessibility/AccessibilitySettings.java @@ -20,7 +20,6 @@ import android.accessibilityservice.AccessibilityServiceInfo; import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.Context; -import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; import android.content.res.Resources; import android.graphics.drawable.Drawable; @@ -52,7 +51,6 @@ import com.android.settings.SettingsPreferenceFragment; import com.android.settings.Utils; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.Indexable; -import com.android.settings.search.SearchIndexableRaw; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; import com.android.settingslib.RestrictedPreference; @@ -727,40 +725,6 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new BaseSearchIndexProvider() { - @Override - public List getRawDataToIndex(Context context, boolean enabled) { - List indexables = new ArrayList<>(); - - PackageManager packageManager = context.getPackageManager(); - AccessibilityManager accessibilityManager = - context.getSystemService(AccessibilityManager.class); - - String screenTitle = context.getResources().getString( - R.string.accessibility_settings); - - // Indexing all services, regardless if enabled. - List services = accessibilityManager - .getInstalledAccessibilityServiceList(); - final int serviceCount = services.size(); - for (int i = 0; i < serviceCount; i++) { - AccessibilityServiceInfo service = services.get(i); - if (service == null || service.getResolveInfo() == null) { - continue; - } - - ServiceInfo serviceInfo = service.getResolveInfo().serviceInfo; - ComponentName componentName = new ComponentName(serviceInfo.packageName, - serviceInfo.name); - - SearchIndexableRaw indexable = new SearchIndexableRaw(context); - indexable.key = componentName.flattenToString(); - indexable.title = service.getResolveInfo().loadLabel(packageManager).toString(); - indexable.screenTitle = screenTitle; - indexables.add(indexable); - } - - return indexables; - } @Override public List getXmlResourcesToIndex(Context context, diff --git a/src/com/android/settings/search/AccessibilityServiceResultLoader.java b/src/com/android/settings/search/AccessibilityServiceResultLoader.java new file mode 100644 index 00000000000..7ffbcfcf712 --- /dev/null +++ b/src/com/android/settings/search/AccessibilityServiceResultLoader.java @@ -0,0 +1,123 @@ +/* + * 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.android.settings.search.InstalledAppResultLoader.getWordDifference; + +import android.accessibilityservice.AccessibilityServiceInfo; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; +import android.graphics.drawable.Drawable; +import android.support.annotation.VisibleForTesting; +import android.support.v4.content.ContextCompat; +import android.view.accessibility.AccessibilityManager; + +import com.android.settings.R; +import com.android.settings.accessibility.AccessibilitySettings; +import com.android.settings.dashboard.SiteMapManager; +import com.android.settings.utils.AsyncLoader; + +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +public class AccessibilityServiceResultLoader extends AsyncLoader> { + + private static final int NAME_NO_MATCH = -1; + + private List mBreadcrumb; + private SiteMapManager mSiteMapManager; + @VisibleForTesting + final String mQuery; + private final AccessibilityManager mAccessibilityManager; + private final PackageManager mPackageManager; + + + public AccessibilityServiceResultLoader(Context context, String query, + SiteMapManager mapManager) { + super(context); + mSiteMapManager = mapManager; + mPackageManager = context.getPackageManager(); + mAccessibilityManager = + (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE); + mQuery = query; + } + + @Override + public Set loadInBackground() { + final Set results = new HashSet<>(); + final Context context = getContext(); + final List services = mAccessibilityManager + .getInstalledAccessibilityServiceList(); + final String screenTitle = context.getString(R.string.accessibility_settings); + for (AccessibilityServiceInfo service : services) { + if (service == null) { + continue; + } + final ResolveInfo resolveInfo = service.getResolveInfo(); + if (service.getResolveInfo() == null) { + continue; + } + final ServiceInfo serviceInfo = resolveInfo.serviceInfo; + final CharSequence title = resolveInfo.loadLabel(mPackageManager); + final int wordDiff = getWordDifference(title.toString(), mQuery); + if (wordDiff == NAME_NO_MATCH) { + continue; + } + final Drawable icon; + if (resolveInfo.getIconResource() == 0) { + icon = ContextCompat.getDrawable(context, R.mipmap.ic_accessibility_generic); + } else { + icon = resolveInfo.loadIcon(mPackageManager); + } + final String componentName = new ComponentName(serviceInfo.packageName, + serviceInfo.name).flattenToString(); + final Intent intent = DatabaseIndexingUtils.buildSubsettingIntent(context, + AccessibilitySettings.class.getName(), componentName, screenTitle); + + results.add(new SearchResult.Builder() + .setTitle(title) + .addBreadcrumbs(getBreadCrumb()) + .setPayload(new ResultPayload(intent)) + .setRank(wordDiff) + .setIcon(icon) + .setStableId(Objects.hash(screenTitle, componentName)) + .build()); + } + return results; + } + + private List getBreadCrumb() { + if (mBreadcrumb == null || mBreadcrumb.isEmpty()) { + final Context context = getContext(); + mBreadcrumb = mSiteMapManager.buildBreadCrumb( + context, AccessibilitySettings.class.getName(), + context.getString(R.string.accessibility_settings)); + } + return mBreadcrumb; + } + + @Override + protected void onDiscardResult(Set result) { + + } +} diff --git a/src/com/android/settings/search/DynamicIndexableContentMonitor.java b/src/com/android/settings/search/DynamicIndexableContentMonitor.java index 07583871d4c..a0e3c021dd7 100644 --- a/src/com/android/settings/search/DynamicIndexableContentMonitor.java +++ b/src/com/android/settings/search/DynamicIndexableContentMonitor.java @@ -17,7 +17,6 @@ package com.android.settings.search; import android.accessibilityservice.AccessibilityService; -import android.accessibilityservice.AccessibilityServiceInfo; import android.app.Activity; import android.app.LoaderManager; import android.content.ContentResolver; @@ -41,13 +40,11 @@ import android.provider.UserDictionary; import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; import android.util.Log; -import android.view.accessibility.AccessibilityManager; import android.view.inputmethod.InputMethod; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; import com.android.internal.content.PackageMonitor; -import com.android.settings.accessibility.AccessibilitySettings; import com.android.settings.inputmethod.AvailableVirtualKeyboardFragment; import com.android.settings.inputmethod.PhysicalKeyboardFragment; import com.android.settings.inputmethod.VirtualKeyboardFragment; @@ -89,7 +86,6 @@ public final class DynamicIndexableContentMonitor implements @VisibleForTesting static void resetForTesting() { InputDevicesMonitor.getInstance().resetForTesting(); - AccessibilityServicesMonitor.getInstance().resetForTesting(); InputMethodServicesMonitor.getInstance().resetForTesting(); } @@ -144,7 +140,6 @@ public final class DynamicIndexableContentMonitor implements InputDevicesMonitor.getInstance().initialize(context, mIndexManager); // Start tracking packages. - AccessibilityServicesMonitor.getInstance().initialize(context, mIndexManager); InputMethodServicesMonitor.getInstance().initialize(context, mIndexManager); } @@ -301,86 +296,17 @@ public final class DynamicIndexableContentMonitor implements private void postPackageAvailable(final String packageName) { getRegisteredHandler().postDelayed(() -> { - AccessibilityServicesMonitor.getInstance().onPackageAvailable(packageName); InputMethodServicesMonitor.getInstance().onPackageAvailable(packageName); }, DELAY_PROCESS_PACKAGE_CHANGE); } private void postPackageUnavailable(final String packageName) { getRegisteredHandler().postDelayed(() -> { - AccessibilityServicesMonitor.getInstance().onPackageUnavailable(packageName); InputMethodServicesMonitor.getInstance().onPackageUnavailable(packageName); }, DELAY_PROCESS_PACKAGE_CHANGE); } } - // A singleton that holds list of available accessibility services and updates search index. - private static class AccessibilityServicesMonitor { - - // Null if not initialized. - @Nullable private DatabaseIndexingManager mIndexManager; - private PackageManager mPackageManager; - private final List mAccessibilityServices = new ArrayList<>(); - - private AccessibilityServicesMonitor() {} - - private static class SingletonHolder { - private static final AccessibilityServicesMonitor INSTANCE = - new AccessibilityServicesMonitor(); - } - - static AccessibilityServicesMonitor getInstance() { - return SingletonHolder.INSTANCE; - } - - @VisibleForTesting - synchronized void resetForTesting() { - mIndexManager = null; - } - - synchronized void initialize(Context context, DatabaseIndexingManager index) { - if (mIndexManager != null) return; - mIndexManager = index; - mPackageManager = context.getPackageManager(); - mAccessibilityServices.clear(); - buildIndex(); - - // Cache accessibility service packages to know when they go away. - AccessibilityManager accessibilityManager = (AccessibilityManager) context - .getSystemService(Context.ACCESSIBILITY_SERVICE); - for (final AccessibilityServiceInfo accessibilityService - : accessibilityManager.getInstalledAccessibilityServiceList()) { - ResolveInfo resolveInfo = accessibilityService.getResolveInfo(); - if (resolveInfo != null && resolveInfo.serviceInfo != null) { - mAccessibilityServices.add(resolveInfo.serviceInfo.packageName); - } - } - } - - private void buildIndex() { - mIndexManager.updateFromClassNameResource(AccessibilitySettings.class.getName(), - true /* includeInSearchResults */); - } - - synchronized void onPackageAvailable(String packageName) { - if (mIndexManager == null) return; - if (mAccessibilityServices.contains(packageName)) return; - - final Intent intent = getAccessibilityServiceIntent(packageName); - final List services = mPackageManager - .queryIntentServices(intent, 0 /* flags */); - if (services == null || services.isEmpty()) return; - mAccessibilityServices.add(packageName); - buildIndex(); - } - - synchronized void onPackageUnavailable(String packageName) { - if (mIndexManager == null) return; - if (!mAccessibilityServices.remove(packageName)) return; - buildIndex(); - } - } - // A singleton that holds list of available input methods and updates search index. // Also it monitors user dictionary changes and updates search index. private static class InputMethodServicesMonitor extends ContentObserver { diff --git a/src/com/android/settings/search/InstalledAppResultLoader.java b/src/com/android/settings/search/InstalledAppResultLoader.java index 6340a61b738..9d80b734a44 100644 --- a/src/com/android/settings/search/InstalledAppResultLoader.java +++ b/src/com/android/settings/search/InstalledAppResultLoader.java @@ -163,8 +163,9 @@ public class InstalledAppResultLoader extends AsyncLoader @VisibleForTesting static final String APP_RESULTS_LOADER_KEY = InstalledAppResultLoader.class.getName(); + @VisibleForTesting + static final String ACCESSIBLITY_LOADER_KEY = AccessibilityServiceResultLoader.class.getName(); @VisibleForTesting static final int MSG_RANKING_TIMED_OUT = 1; @@ -262,11 +264,16 @@ public class SearchResultsAdapter extends RecyclerView.Adapter getSortedLoadedResults(DB_RESULTS_LOADER_KEY); List installedAppResults = getSortedLoadedResults(APP_RESULTS_LOADER_KEY); + List accessibilityResults = + getSortedLoadedResults(ACCESSIBLITY_LOADER_KEY); + int dbSize = databaseResults.size(); int appSize = installedAppResults.size(); + int a11ySize = accessibilityResults.size(); int dbIndex = 0; int appIndex = 0; + int a11yIndex = 0; int rank = SearchResult.TOP_RANK; mStaticallyRankedSearchResults.clear(); @@ -277,6 +284,9 @@ public class SearchResultsAdapter extends RecyclerView.Adapter while ((appIndex < appSize) && (installedAppResults.get(appIndex).rank == rank)) { mStaticallyRankedSearchResults.add(installedAppResults.get(appIndex++)); } + while ((a11yIndex < a11ySize) && (accessibilityResults.get(a11yIndex).rank == rank)) { + mStaticallyRankedSearchResults.add(accessibilityResults.get(a11yIndex++)); + } rank++; } @@ -286,6 +296,9 @@ public class SearchResultsAdapter extends RecyclerView.Adapter while (appIndex < appSize) { mStaticallyRankedSearchResults.add(installedAppResults.get(appIndex++)); } + while(a11yIndex < a11ySize) { + mStaticallyRankedSearchResults.add(accessibilityResults.get(a11yIndex++)); + } } private void updateSearchResults() { @@ -318,10 +331,13 @@ public class SearchResultsAdapter extends RecyclerView.Adapter getUnsortedLoadedResults(DB_RESULTS_LOADER_KEY); List installedAppResults = getSortedLoadedResults(APP_RESULTS_LOADER_KEY); + List accessibilityResults = + getSortedLoadedResults(ACCESSIBLITY_LOADER_KEY); int dbSize = databaseResults.size(); int appSize = installedAppResults.size(); + int a11ySize = accessibilityResults.size(); - final List asyncRankingResults = new ArrayList<>(dbSize + appSize); + final List asyncRankingResults = new ArrayList<>(dbSize + appSize + a11ySize); TreeSet dbResultsSortedByScores = new TreeSet<>( new Comparator() { @Override @@ -339,8 +355,9 @@ public class SearchResultsAdapter extends RecyclerView.Adapter }); dbResultsSortedByScores.addAll(databaseResults); asyncRankingResults.addAll(dbResultsSortedByScores); - // App results are not ranked by async ranking and appended at the end of the list. + // Other results are not ranked by async ranking and appended at the end of the list. asyncRankingResults.addAll(installedAppResults); + asyncRankingResults.addAll(accessibilityResults); return asyncRankingResults; } diff --git a/tests/robotests/src/com/android/settings/search/AccessibilityServiceResultLoaderTest.java b/tests/robotests/src/com/android/settings/search/AccessibilityServiceResultLoaderTest.java new file mode 100644 index 00000000000..4896dc48dd4 --- /dev/null +++ b/tests/robotests/src/com/android/settings/search/AccessibilityServiceResultLoaderTest.java @@ -0,0 +1,114 @@ +/* + * 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 static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.accessibilityservice.AccessibilityServiceInfo; +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.view.accessibility.AccessibilityManager; + +import com.android.settings.TestConfig; +import com.android.settings.dashboard.SiteMapManager; +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +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.annotation.Config; + +import java.util.ArrayList; +import java.util.List; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class AccessibilityServiceResultLoaderTest { + + private static final String QUERY = "test_query"; + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private Context mContext; + @Mock + private PackageManager mPackageManager; + @Mock + private AccessibilityManager mAccessibilityManager; + @Mock + private SiteMapManager mSiteMapManager; + + private AccessibilityServiceResultLoader mLoader; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + when(mContext.getSystemService(Context.ACCESSIBILITY_SERVICE)) + .thenReturn(mAccessibilityManager); + when(mContext.getPackageManager()).thenReturn(mPackageManager); + + mLoader = new AccessibilityServiceResultLoader(mContext, QUERY, mSiteMapManager); + } + + @Test + public void query_noService_shouldNotReturnAnything() { + assertThat(mLoader.loadInBackground()).isEmpty(); + } + + @Test + public void query_hasServiceMatchingTitle_shouldReturnResult() { + addFakeAccessibilityService(); + + List results = new ArrayList<>(mLoader.loadInBackground()); + assertThat(results).hasSize(1); + + SearchResult result = results.get(0); + assertThat(result.title).isEqualTo(QUERY); + } + + @Test + public void query_serviceDoesNotMatchTitle_shouldReturnResult() { + addFakeAccessibilityService(); + + mLoader = new AccessibilityServiceResultLoader(mContext, + QUERY + "no_match", mSiteMapManager); + + assertThat(mLoader.loadInBackground()).isEmpty(); + } + + private void addFakeAccessibilityService() { + final List services = new ArrayList<>(); + final AccessibilityServiceInfo info = mock(AccessibilityServiceInfo.class); + final ResolveInfo resolveInfo = mock(ResolveInfo.class); + when(info.getResolveInfo()).thenReturn(resolveInfo); + when(resolveInfo.loadIcon(mPackageManager)).thenReturn(new ColorDrawable(Color.BLUE)); + when(resolveInfo.loadLabel(mPackageManager)).thenReturn(QUERY); + resolveInfo.serviceInfo = new ServiceInfo(); + resolveInfo.serviceInfo.packageName = "pkg"; + resolveInfo.serviceInfo.name = "class"; + services.add(info); + + when(mAccessibilityManager.getInstalledAccessibilityServiceList()).thenReturn(services); + } +} diff --git a/tests/robotests/src/com/android/settings/search/DynamicIndexableContentMonitorTest.java b/tests/robotests/src/com/android/settings/search/DynamicIndexableContentMonitorTest.java index 64a658eccca..26c89d5e9b8 100644 --- a/tests/robotests/src/com/android/settings/search/DynamicIndexableContentMonitorTest.java +++ b/tests/robotests/src/com/android/settings/search/DynamicIndexableContentMonitorTest.java @@ -16,6 +16,19 @@ package com.android.settings.search; +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.only; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + import android.accessibilityservice.AccessibilityServiceInfo; import android.app.Activity; import android.app.Application; @@ -40,15 +53,14 @@ import android.provider.UserDictionary; import android.view.inputmethod.InputMethodInfo; import com.android.internal.content.PackageMonitor; -import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; -import com.android.settings.accessibility.AccessibilitySettings; import com.android.settings.inputmethod.AvailableVirtualKeyboardFragment; import com.android.settings.inputmethod.PhysicalKeyboardFragment; import com.android.settings.inputmethod.VirtualKeyboardFragment; import com.android.settings.language.LanguageAndInputSettings; import com.android.settings.print.PrintSettingsFragment; import com.android.settings.testutils.DatabaseTestUtils; +import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.ShadowActivityWithLoadManager; import com.android.settings.testutils.shadow.ShadowContextImplWithRegisterReceiver; import com.android.settings.testutils.shadow.ShadowInputManager; @@ -77,19 +89,6 @@ import java.util.Collection; import java.util.Collections; import java.util.List; -import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyBoolean; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.only; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - @RunWith(SettingsRobolectricTestRunner.class) @Config( manifest = TestConfig.MANIFEST_PATH, @@ -271,67 +270,6 @@ public class DynamicIndexableContentMonitorTest { verifyIncrementalIndexing(PhysicalKeyboardFragment.class); } - @Test - public void testAccessibilityServicesMonitor() throws Exception { - mMonitor.register(mActivity, LOADER_ID, mIndexManager, true /* isUserUnlocked */); - - verifyIncrementalIndexing(AccessibilitySettings.class); - - /* - * When an accessibility service package is installed, incremental indexing happen. - */ - reset(mIndexManager); - - installAccessibilityService(A11Y_PACKAGE_1); - - verifyIncrementalIndexing(AccessibilitySettings.class); - - /* - * When another accessibility service package is installed, incremental indexing happens. - */ - reset(mIndexManager); - - installAccessibilityService(A11Y_PACKAGE_2); - - verifyIncrementalIndexing(AccessibilitySettings.class); - - /* - * When an accessibility service is disabled, rebuild indexing happens. - */ - reset(mIndexManager); - - disableInstalledPackage(A11Y_PACKAGE_1); - - verifyIncrementalIndexing(AccessibilitySettings.class); - - /* - * When an accessibility service is enabled, incremental indexing happens. - */ - reset(mIndexManager); - - enableInstalledPackage(A11Y_PACKAGE_1); - - verifyIncrementalIndexing(AccessibilitySettings.class); - - /* - * When an accessibility service package is uninstalled, rebuild indexing happens. - */ - reset(mIndexManager); - - uninstallAccessibilityService(A11Y_PACKAGE_1); - - verifyIncrementalIndexing(AccessibilitySettings.class); - - /* - * When an input method service package is installed, nothing happens. - */ - reset(mIndexManager); - - installInputMethodService(IME_PACKAGE_1); - - verifyNoIndexing(AccessibilitySettings.class); - } - @Test public void testInputMethodServicesMonitor() throws Exception { mMonitor.register(mActivity, LOADER_ID, mIndexManager, true /* isUserUnlocked */); diff --git a/tests/robotests/src/com/android/settings/search/InstalledAppResultLoaderTest.java b/tests/robotests/src/com/android/settings/search/InstalledAppResultLoaderTest.java index d0a200dbccd..19854fcf09e 100644 --- a/tests/robotests/src/com/android/settings/search/InstalledAppResultLoaderTest.java +++ b/tests/robotests/src/com/android/settings/search/InstalledAppResultLoaderTest.java @@ -17,6 +17,20 @@ package com.android.settings.search; +import static android.content.pm.ApplicationInfo.FLAG_SYSTEM; +import static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyList; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; @@ -26,12 +40,12 @@ import android.os.UserHandle; import android.os.UserManager; import com.android.settings.R; -import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; import com.android.settings.applications.PackageManagerWrapper; import com.android.settings.dashboard.SiteMapManager; import com.android.settings.testutils.ApplicationTestUtils; import com.android.settings.testutils.FakeFeatureFactory; +import com.android.settings.testutils.SettingsRobolectricTestRunner; import org.junit.Before; import org.junit.Test; @@ -50,20 +64,6 @@ import java.util.List; import java.util.Set; import java.util.stream.Collectors; -import static android.content.pm.ApplicationInfo.FLAG_SYSTEM; -import static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; -import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyList; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - @RunWith(SettingsRobolectricTestRunner.class) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) public class InstalledAppResultLoaderTest { @@ -82,8 +82,8 @@ public class InstalledAppResultLoaderTest { @Before public void setUp() { MockitoAnnotations.initMocks(this); - FakeFeatureFactory.setupForTest(mContext); - FakeFeatureFactory factory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext); + + final FakeFeatureFactory factory = FakeFeatureFactory.setupForTest(mContext); when(factory.searchFeatureProvider.getSiteMapManager()) .thenReturn(mSiteMapManager); final List infos = new ArrayList<>(); diff --git a/tests/robotests/src/com/android/settings/search/MockAccessiblityLoader.java b/tests/robotests/src/com/android/settings/search/MockAccessiblityLoader.java new file mode 100644 index 00000000000..aa9b778e299 --- /dev/null +++ b/tests/robotests/src/com/android/settings/search/MockAccessiblityLoader.java @@ -0,0 +1,39 @@ +/* + * 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.Context; + +import java.util.HashSet; +import java.util.Set; + +public class MockAccessiblityLoader extends AccessibilityServiceResultLoader { + + public MockAccessiblityLoader(Context context) { + super(context, "test_query", null); + } + + @Override + public Set loadInBackground() { + return new HashSet<>(); + } + + @Override + protected void onDiscardResult(Set result) { + + } +} diff --git a/tests/robotests/src/com/android/settings/search/SearchFragmentTest.java b/tests/robotests/src/com/android/settings/search/SearchFragmentTest.java index bc05c165109..658880528ab 100644 --- a/tests/robotests/src/com/android/settings/search/SearchFragmentTest.java +++ b/tests/robotests/src/com/android/settings/search/SearchFragmentTest.java @@ -81,6 +81,8 @@ public class SearchFragmentTest { private DatabaseResultLoader mDatabaseResultLoader; @Mock private InstalledAppResultLoader mInstalledAppResultLoader; + @Mock + private AccessibilityServiceResultLoader mAccessibilityServiceResultLoader; @Mock private SavedQueryLoader mSavedQueryLoader; @@ -113,6 +115,9 @@ public class SearchFragmentTest { when(mFeatureFactory.searchFeatureProvider .getInstalledAppSearchLoader(any(Context.class), anyString())) .thenReturn(mInstalledAppResultLoader); + when(mFeatureFactory.searchFeatureProvider + .getAccessibilityServiceResultLoader(any(Context.class), anyString())) + .thenReturn(mAccessibilityServiceResultLoader); when(mFeatureFactory.searchFeatureProvider.getSavedQueryLoader(any(Context.class))) .thenReturn(mSavedQueryLoader); @@ -170,6 +175,9 @@ public class SearchFragmentTest { when(mFeatureFactory.searchFeatureProvider .getInstalledAppSearchLoader(any(Context.class), anyString())) .thenReturn(mInstalledAppResultLoader); + when(mFeatureFactory.searchFeatureProvider + .getAccessibilityServiceResultLoader(any(Context.class), anyString())) + .thenReturn(mAccessibilityServiceResultLoader); when(mFeatureFactory.searchFeatureProvider.getSavedQueryLoader(any(Context.class))) .thenReturn(mSavedQueryLoader); @@ -225,6 +233,9 @@ public class SearchFragmentTest { when(mFeatureFactory.searchFeatureProvider .getInstalledAppSearchLoader(any(Context.class), anyString())) .thenReturn(mInstalledAppResultLoader); + when(mFeatureFactory.searchFeatureProvider + .getAccessibilityServiceResultLoader(any(Context.class), anyString())) + .thenReturn(mAccessibilityServiceResultLoader); when(mFeatureFactory.searchFeatureProvider.getSavedQueryLoader(any(Context.class))) .thenReturn(mSavedQueryLoader); ActivityController activityController = @@ -256,6 +267,9 @@ public class SearchFragmentTest { when(mFeatureFactory.searchFeatureProvider .getInstalledAppSearchLoader(any(Context.class), anyString())) .thenReturn(mInstalledAppResultLoader); + when(mFeatureFactory.searchFeatureProvider + .getAccessibilityServiceResultLoader(any(Context.class), anyString())) + .thenReturn(mAccessibilityServiceResultLoader); when(mFeatureFactory.searchFeatureProvider.getSavedQueryLoader(any(Context.class))) .thenReturn(mSavedQueryLoader); @@ -333,6 +347,9 @@ public class SearchFragmentTest { when(mFeatureFactory.searchFeatureProvider .getInstalledAppSearchLoader(any(Context.class), anyString())) .thenReturn(new MockAppLoader(RuntimeEnvironment.application)); + when(mFeatureFactory.searchFeatureProvider + .getAccessibilityServiceResultLoader(any(Context.class), anyString())) + .thenReturn(new MockAccessiblityLoader(RuntimeEnvironment.application)); when(mFeatureFactory.searchFeatureProvider.getSavedQueryLoader(any(Context.class))) .thenReturn(mSavedQueryLoader); ActivityController activityController =