Merge "Move a11y indexing from DynamicContentMonitor to loader" into oc-mr1-dev

This commit is contained in:
TreeHugger Robot
2017-08-04 20:50:26 +00:00
committed by Android (Google) Code Review
13 changed files with 375 additions and 213 deletions

View File

@@ -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<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) {
List<SearchIndexableRaw> 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<AccessibilityServiceInfo> 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<SearchIndexableResource> getXmlResourcesToIndex(Context context,

View File

@@ -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<Set<? extends SearchResult>> {
private static final int NAME_NO_MATCH = -1;
private List<String> 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<? extends SearchResult> loadInBackground() {
final Set<SearchResult> results = new HashSet<>();
final Context context = getContext();
final List<AccessibilityServiceInfo> 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<String> 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<? extends SearchResult> result) {
}
}

View File

@@ -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<String> 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<ResolveInfo> 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 {

View File

@@ -163,8 +163,9 @@ public class InstalledAppResultLoader extends AsyncLoader<Set<? extends SearchRe
* appName: Abcde, query: bc, Returns NAME_NO_MATCH
* appName: Abcde, query: xyz, Returns NAME_NO_MATCH
* appName: Abc de, query: de, Returns 4
* TODO: Move this to a common util class.
*/
private int getWordDifference(String appName, String query) {
static int getWordDifference(String appName, String query) {
if (TextUtils.isEmpty(appName) || TextUtils.isEmpty(query)) {
return NAME_NO_MATCH;
}

View File

@@ -42,6 +42,12 @@ public interface SearchFeatureProvider {
*/
InstalledAppResultLoader getInstalledAppSearchLoader(Context context, String query);
/**
* Returns a new loader to search accessibility services.
*/
AccessibilityServiceResultLoader getAccessibilityServiceResultLoader(Context context,
String query);
/**
* Returns a new loader to get all recently saved queries search terms.
*/
@@ -95,8 +101,8 @@ public interface SearchFeatureProvider {
/**
* Query search results based on the input query.
*
* @param context application context
* @param query input user query
* @param context application context
* @param query input user query
* @param searchResultsRankerCallback {@link SearchResultsRankerCallback}
*/
default void querySearchResults(Context context, String query,
@@ -112,8 +118,8 @@ public interface SearchFeatureProvider {
/**
* Notify that a search result is clicked.
*
* @param context application context
* @param query input user query
* @param context application context
* @param query input user query
* @param searchResult clicked result
*/
default void searchResultClicked(Context context, String query, SearchResult searchResult) {

View File

@@ -54,6 +54,13 @@ public class SearchFeatureProviderImpl implements SearchFeatureProvider {
cleanQuery(query), getSiteMapManager());
}
@Override
public AccessibilityServiceResultLoader getAccessibilityServiceResultLoader(Context context,
String query) {
return new AccessibilityServiceResultLoader(context, cleanQuery(query),
getSiteMapManager());
}
@Override
public SavedQueryLoader getSavedQueryLoader(Context context) {
return new SavedQueryLoader(context);

View File

@@ -82,8 +82,10 @@ public class SearchFragment extends InstrumentedFragment implements SearchView.O
static final int LOADER_ID_DATABASE = 1;
@VisibleForTesting
static final int LOADER_ID_INSTALLED_APPS = 2;
@VisibleForTesting
static final int LOADER_ID_ACCESSIBILITY_SERVICES = 3;
private static final int NUM_QUERY_LOADERS = 2;
private static final int NUM_QUERY_LOADERS = 3;
@VisibleForTesting
AtomicInteger mUnfinishedLoadersCount = new AtomicInteger(NUM_QUERY_LOADERS);
@@ -281,6 +283,7 @@ public class SearchFragment extends InstrumentedFragment implements SearchView.O
final LoaderManager loaderManager = getLoaderManager();
loaderManager.destroyLoader(LOADER_ID_DATABASE);
loaderManager.destroyLoader(LOADER_ID_INSTALLED_APPS);
loaderManager.destroyLoader(LOADER_ID_ACCESSIBILITY_SERVICES);
mShowingSavedQuery = true;
mSavedQueryController.loadSavedQueries();
mSearchFeatureProvider.hideFeedbackButton();
@@ -309,6 +312,8 @@ public class SearchFragment extends InstrumentedFragment implements SearchView.O
return mSearchFeatureProvider.getDatabaseSearchLoader(activity, mQuery);
case LOADER_ID_INSTALLED_APPS:
return mSearchFeatureProvider.getInstalledAppSearchLoader(activity, mQuery);
case LOADER_ID_ACCESSIBILITY_SERVICES:
return mSearchFeatureProvider.getAccessibilityServiceResultLoader(activity, mQuery);
default:
return null;
}
@@ -341,8 +346,11 @@ public class SearchFragment extends InstrumentedFragment implements SearchView.O
mSavedQueryController.loadSavedQueries();
} else {
final LoaderManager loaderManager = getLoaderManager();
loaderManager.initLoader(LOADER_ID_DATABASE, null, this);
loaderManager.initLoader(LOADER_ID_INSTALLED_APPS, null, this);
loaderManager.initLoader(LOADER_ID_DATABASE, null /* args */, this /* callback */);
loaderManager.initLoader(
LOADER_ID_INSTALLED_APPS, null /* args */, this /* callback */);
loaderManager.initLoader(
LOADER_ID_ACCESSIBILITY_SERVICES, null /* args */, this /* callback */);
}
requery();
@@ -382,6 +390,8 @@ public class SearchFragment extends InstrumentedFragment implements SearchView.O
mUnfinishedLoadersCount.set(NUM_QUERY_LOADERS);
loaderManager.restartLoader(LOADER_ID_DATABASE, null /* args */, this /* callback */);
loaderManager.restartLoader(LOADER_ID_INSTALLED_APPS, null /* args */, this /* callback */);
loaderManager.restartLoader(LOADER_ID_ACCESSIBILITY_SERVICES, null /* args */,
this /* callback */);
}
public String getQuery() {

View File

@@ -56,6 +56,8 @@ public class SearchResultsAdapter extends RecyclerView.Adapter<SearchViewHolder>
@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<SearchViewHolder>
getSortedLoadedResults(DB_RESULTS_LOADER_KEY);
List<? extends SearchResult> installedAppResults =
getSortedLoadedResults(APP_RESULTS_LOADER_KEY);
List<? extends SearchResult> 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<SearchViewHolder>
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<SearchViewHolder>
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<SearchViewHolder>
getUnsortedLoadedResults(DB_RESULTS_LOADER_KEY);
List<? extends SearchResult> installedAppResults =
getSortedLoadedResults(APP_RESULTS_LOADER_KEY);
List<? extends SearchResult> accessibilityResults =
getSortedLoadedResults(ACCESSIBLITY_LOADER_KEY);
int dbSize = databaseResults.size();
int appSize = installedAppResults.size();
int a11ySize = accessibilityResults.size();
final List<SearchResult> asyncRankingResults = new ArrayList<>(dbSize + appSize);
final List<SearchResult> asyncRankingResults = new ArrayList<>(dbSize + appSize + a11ySize);
TreeSet<SearchResult> dbResultsSortedByScores = new TreeSet<>(
new Comparator<SearchResult>() {
@Override
@@ -339,8 +355,9 @@ public class SearchResultsAdapter extends RecyclerView.Adapter<SearchViewHolder>
});
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;
}

View File

@@ -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<? extends SearchResult> 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<AccessibilityServiceInfo> 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);
}
}

View File

@@ -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 */);

View File

@@ -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<UserInfo> infos = new ArrayList<>();

View File

@@ -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<? extends SearchResult> loadInBackground() {
return new HashSet<>();
}
@Override
protected void onDiscardResult(Set<? extends SearchResult> result) {
}
}

View File

@@ -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<SearchActivity> 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<SearchActivity> activityController =