diff --git a/res/xml/available_virtual_keyboard.xml b/res/xml/available_virtual_keyboard.xml new file mode 100644 index 00000000000..9a0b3c62ab1 --- /dev/null +++ b/res/xml/available_virtual_keyboard.xml @@ -0,0 +1,23 @@ + + + + + + \ No newline at end of file diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java index 928eae1114d..f9b849eb796 100644 --- a/src/com/android/settings/SettingsActivity.java +++ b/src/com/android/settings/SettingsActivity.java @@ -60,7 +60,6 @@ import com.android.settings.dashboard.DashboardFeatureProvider; import com.android.settings.dashboard.DashboardSummary; import com.android.settings.development.DevelopmentSettings; import com.android.settings.overlay.FeatureFactory; -import com.android.settings.search.DynamicIndexableContentMonitor; import com.android.settings.search.SearchActivity; import com.android.settings.wfd.WifiDisplaySettings; import com.android.settings.widget.SwitchBar; @@ -78,8 +77,6 @@ public class SettingsActivity extends SettingsDrawerActivity private static final String LOG_TAG = "Settings"; - public static final int LOADER_ID_INDEXABLE_CONTENT_MONITOR = 1; - // Constants for state save/restore private static final String SAVE_KEY_CATEGORIES = ":settings:categories"; @VisibleForTesting @@ -184,8 +181,6 @@ public class SettingsActivity extends SettingsDrawerActivity } }; - private DynamicIndexableContentMonitor mDynamicIndexableContentMonitor; - private SwitchBar mSwitchBar; private Button mNextButton; @@ -538,10 +533,6 @@ public class SettingsActivity extends SettingsDrawerActivity new IntentFilter(DevelopmentSettingsEnabler.DEVELOPMENT_SETTINGS_CHANGED_ACTION)); registerReceiver(mBatteryInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); - if (mDynamicIndexableContentMonitor == null) { - mDynamicIndexableContentMonitor = new DynamicIndexableContentMonitor(); - } - mDynamicIndexableContentMonitor.register(this, LOADER_ID_INDEXABLE_CONTENT_MONITOR); updateTilesList(); } @@ -552,9 +543,6 @@ public class SettingsActivity extends SettingsDrawerActivity LocalBroadcastManager.getInstance(this).unregisterReceiver(mDevelopmentSettingsListener); mDevelopmentSettingsListener = null; unregisterReceiver(mBatteryInfoReceiver); - if (mDynamicIndexableContentMonitor != null) { - mDynamicIndexableContentMonitor.unregister(this, LOADER_ID_INDEXABLE_CONTENT_MONITOR); - } } @Override diff --git a/src/com/android/settings/inputmethod/AvailableVirtualKeyboardFragment.java b/src/com/android/settings/inputmethod/AvailableVirtualKeyboardFragment.java index a7862ae2401..48b0b4ada4f 100644 --- a/src/com/android/settings/inputmethod/AvailableVirtualKeyboardFragment.java +++ b/src/com/android/settings/inputmethod/AvailableVirtualKeyboardFragment.java @@ -21,7 +21,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Activity; import android.app.admin.DevicePolicyManager; -import android.content.ComponentName; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; @@ -31,17 +30,15 @@ import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; -import android.support.v7.preference.PreferenceScreen; +import android.provider.SearchIndexableResource; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; -import android.view.inputmethod.InputMethodSubtype; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; import com.android.settings.SettingsPreferenceFragment; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.Indexable; -import com.android.settings.search.SearchIndexableRaw; import com.android.settingslib.inputmethod.InputMethodAndSubtypeUtil; import com.android.settingslib.inputmethod.InputMethodPreference; import com.android.settingslib.inputmethod.InputMethodSettingValuesWrapper; @@ -60,10 +57,9 @@ public final class AvailableVirtualKeyboardFragment extends SettingsPreferenceFr @Override public void onCreatePreferences(Bundle bundle, String s) { + addPreferencesFromResource(R.xml.available_virtual_keyboard); Activity activity = getActivity(); - PreferenceScreen screen = getPreferenceManager().createPreferenceScreen(activity); - screen.setTitle(activity.getString(R.string.available_virtual_keyboard_category)); - setPreferenceScreen(screen); + mInputMethodSettingValues = InputMethodSettingValuesWrapper.getInstance(activity); mImm = activity.getSystemService(InputMethodManager.class); mDpm = activity.getSystemService(DevicePolicyManager.class); @@ -105,7 +101,7 @@ public final class AvailableVirtualKeyboardFragment extends SettingsPreferenceFr } try { return packageManager.getDrawable(packageName, resId, applicationInfo); - } catch (Exception e){ + } catch (Exception e) { return null; } } @@ -172,48 +168,16 @@ public final class AvailableVirtualKeyboardFragment extends SettingsPreferenceFr } } - private static List getAllSubtypesOf(final InputMethodInfo imi) { - final int subtypeCount = imi.getSubtypeCount(); - final List allSubtypes = new ArrayList<>(subtypeCount); - for (int index = 0; index < subtypeCount; index++) { - allSubtypes.add(imi.getSubtypeAt(index)); - } - return allSubtypes; - } - - static List buildSearchIndexOfInputMethods(final Context context, - final List inputMethods, final String screenTitle) { - final List indexes = new ArrayList<>(); - for (int i = 0; i < inputMethods.size(); i++) { - final InputMethodInfo imi = inputMethods.get(i); - final ServiceInfo serviceInfo = imi.getServiceInfo(); - final SearchIndexableRaw index = new SearchIndexableRaw(context); - index.key = new ComponentName(serviceInfo.packageName, serviceInfo.name) - .flattenToString(); - index.title = imi.loadLabel(context.getPackageManager()).toString(); - index.summaryOn = index.summaryOff = InputMethodAndSubtypeUtil - .getSubtypeLocaleNameListAsSentence(getAllSubtypesOf(imi), context, imi); - index.screenTitle = screenTitle; - indexes.add(index); - } - return indexes; - } - - public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = + public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new BaseSearchIndexProvider() { - @Override - public List getRawDataToIndex(Context context, boolean enabled) { - final InputMethodManager imm = context.getSystemService(InputMethodManager.class); - final List enabledInputMethods = imm.getEnabledInputMethodList(); - final List disabledInputMethods = new ArrayList<>(); - for (final InputMethodInfo imi : imm.getInputMethodList()) { - if (!enabledInputMethods.contains(imi)) { - disabledInputMethods.add(imi); + @Override + public List getXmlResourcesToIndex(Context context, + boolean enabled) { + List res = new ArrayList<>(); + SearchIndexableResource index = new SearchIndexableResource(context); + index.xmlResId = R.xml.available_virtual_keyboard; + res.add(index); + return res; } - } - final String screenTitle = context.getString( - R.string.available_virtual_keyboard_category); - return buildSearchIndexOfInputMethods(context, disabledInputMethods, screenTitle); - } - }; + }; } diff --git a/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java b/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java index 42eff159747..83d501d0a35 100644 --- a/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java +++ b/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java @@ -31,6 +31,7 @@ import android.hardware.input.KeyboardLayout; import android.os.Bundle; import android.os.Handler; import android.os.UserHandle; +import android.provider.SearchIndexableResource; import android.provider.Settings.Secure; import android.support.v14.preference.SwitchPreference; import android.support.v7.preference.Preference; @@ -51,11 +52,11 @@ import com.android.settings.Settings; import com.android.settings.SettingsPreferenceFragment; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.Indexable; -import com.android.settings.search.SearchIndexableRaw; import com.android.settingslib.inputmethod.InputMethodAndSubtypeUtil; import java.text.Collator; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -288,6 +289,7 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment final PhysicalKeyboardFragment mPhysicalKeyboardFragment; @NonNull final List mHardKeyboards; + public Callbacks( @NonNull Context context, @NonNull PhysicalKeyboardFragment physicalKeyboardFragment, @@ -532,43 +534,14 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment } } - public static List getPhysicalFullKeyboards() { - List keyboards = null; - for (final int deviceId : InputDevice.getDeviceIds()) { - final InputDevice device = InputDevice.getDevice(deviceId); - if (device != null && !device.isVirtual() && device.isFullKeyboard()) { - if (keyboards == null) keyboards = new ArrayList<>(); - keyboards.add(device); - } - } - return (keyboards == null) ? Collections.emptyList() : keyboards; - } - public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new BaseSearchIndexProvider() { - @Override - public List getRawDataToIndex(Context context, boolean enabled) { - final InputManager inputManager = (InputManager) context.getSystemService( - Context.INPUT_SERVICE); - final String screenTitle = context.getString(R.string.physical_keyboard_title); - final List indexes = new ArrayList<>(); - for (final InputDevice device : getPhysicalFullKeyboards()) { - final String keyboardLayoutDescriptor = inputManager - .getCurrentKeyboardLayoutForInputDevice(device.getIdentifier()); - final KeyboardLayout keyboardLayout = (keyboardLayoutDescriptor != null) - ? inputManager.getKeyboardLayout(keyboardLayoutDescriptor) : null; - final String summary = (keyboardLayout != null) - ? keyboardLayout.toString() - : context.getString(R.string.keyboard_layout_default_label); - final SearchIndexableRaw index = new SearchIndexableRaw(context); - index.key = device.getName(); - index.title = device.getName(); - index.summaryOn = summary; - index.summaryOff = summary; - index.screenTitle = screenTitle; - indexes.add(index); - } - return indexes; - } - }; + @Override + public List getXmlResourcesToIndex( + Context context, boolean enabled) { + final SearchIndexableResource sir = new SearchIndexableResource(context); + sir.xmlResId = R.xml.physical_keyboard_settings; + return Arrays.asList(sir); + } + }; } diff --git a/src/com/android/settings/inputmethod/VirtualKeyboardFragment.java b/src/com/android/settings/inputmethod/VirtualKeyboardFragment.java index 7b7c5992e81..fbe9690bb6d 100644 --- a/src/com/android/settings/inputmethod/VirtualKeyboardFragment.java +++ b/src/com/android/settings/inputmethod/VirtualKeyboardFragment.java @@ -23,6 +23,7 @@ import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; +import android.provider.SearchIndexableResource; import android.support.v7.preference.Preference; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; @@ -33,14 +34,12 @@ import com.android.settings.R; import com.android.settings.SettingsPreferenceFragment; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.Indexable; -import com.android.settings.search.SearchIndexableRaw; import com.android.settingslib.inputmethod.InputMethodAndSubtypeUtil; import com.android.settingslib.inputmethod.InputMethodPreference; import java.text.Collator; import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; +import java.util.Arrays; import java.util.List; public final class VirtualKeyboardFragment extends SettingsPreferenceFragment implements Indexable { @@ -121,13 +120,19 @@ public final class VirtualKeyboardFragment extends SettingsPreferenceFragment im public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new BaseSearchIndexProvider() { - @Override - public List getRawDataToIndex(Context context, boolean enabled) { - final InputMethodManager imm = context.getSystemService(InputMethodManager.class); - final List enabledInputMethods = imm.getEnabledInputMethodList(); - final String screenTitle = context.getString(R.string.virtual_keyboard_category); - return AvailableVirtualKeyboardFragment - .buildSearchIndexOfInputMethods(context, enabledInputMethods, screenTitle); - } - }; + @Override + public List getXmlResourcesToIndex( + Context context, boolean enabled) { + final SearchIndexableResource sir = new SearchIndexableResource(context); + sir.xmlResId = R.xml.virtual_keyboard_settings; + return Arrays.asList(sir); + } + + @Override + public List getNonIndexableKeys(Context context) { + final List keys = super.getNonIndexableKeys(context); + keys.add("add_virtual_keyboard_screen"); + return keys; + } + }; } diff --git a/src/com/android/settings/language/LanguageAndInputSettings.java b/src/com/android/settings/language/LanguageAndInputSettings.java index fbcb02f5cbc..4affc6edbc6 100644 --- a/src/com/android/settings/language/LanguageAndInputSettings.java +++ b/src/com/android/settings/language/LanguageAndInputSettings.java @@ -52,6 +52,7 @@ public class LanguageAndInputSettings extends DashboardFragment { private static final String TAG = "LangAndInputSettings"; private static final String KEY_TEXT_TO_SPEECH = "tts_settings_summary"; + private static final String KEY_PHYSICAL_KEYBOARD = "physical_keyboard_pref"; @Override public int getMetricsCategory() { @@ -174,6 +175,7 @@ public class LanguageAndInputSettings extends DashboardFragment { List keys = super.getNonIndexableKeys(context); // Duplicates in summary and details pages. keys.add(KEY_TEXT_TO_SPEECH); + keys.add(KEY_PHYSICAL_KEYBOARD); return keys; } diff --git a/src/com/android/settings/search/DynamicIndexableContentMonitor.java b/src/com/android/settings/search/DynamicIndexableContentMonitor.java deleted file mode 100644 index a0e3c021dd7..00000000000 --- a/src/com/android/settings/search/DynamicIndexableContentMonitor.java +++ /dev/null @@ -1,415 +0,0 @@ -/* - * Copyright (C) 2014 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.accessibilityservice.AccessibilityService; -import android.app.Activity; -import android.app.LoaderManager; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.Loader; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.content.pm.ServiceInfo; -import android.database.ContentObserver; -import android.hardware.input.InputManager; -import android.net.Uri; -import android.os.Bundle; -import android.os.UserHandle; -import android.os.UserManager; -import android.print.PrintManager; -import android.print.PrintServicesLoader; -import android.printservice.PrintServiceInfo; -import android.provider.Settings; -import android.provider.UserDictionary; -import android.support.annotation.Nullable; -import android.support.annotation.VisibleForTesting; -import android.util.Log; -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.inputmethod.AvailableVirtualKeyboardFragment; -import com.android.settings.inputmethod.PhysicalKeyboardFragment; -import com.android.settings.inputmethod.VirtualKeyboardFragment; -import com.android.settings.language.LanguageAndInputSettings; -import com.android.settings.overlay.FeatureFactory; -import com.android.settings.print.PrintSettingsFragment; - -import java.util.ArrayList; -import java.util.List; - -public final class DynamicIndexableContentMonitor implements - LoaderManager.LoaderCallbacks> { - // Shorten the class name because log TAG can be at most 23 chars. - private static final String TAG = "DynamicContentMonitor"; - - private static final long DELAY_PROCESS_PACKAGE_CHANGE = 2000; - // A PackageMonitor shared among Settings activities. - private static final PackageChangeMonitor PACKAGE_CHANGE_MONITOR = new PackageChangeMonitor(); - - // Null if not initialized. - @Nullable private DatabaseIndexingManager mIndexManager; - private Context mContext; - private boolean mHasFeaturePrinting; - - @VisibleForTesting - static Intent getAccessibilityServiceIntent(String packageName) { - final Intent intent = new Intent(AccessibilityService.SERVICE_INTERFACE); - intent.setPackage(packageName); - return intent; - } - - @VisibleForTesting - static Intent getIMEServiceIntent(String packageName) { - final Intent intent = new Intent(InputMethod.SERVICE_INTERFACE); - intent.setPackage(packageName); - return intent; - } - - @VisibleForTesting - static void resetForTesting() { - InputDevicesMonitor.getInstance().resetForTesting(); - InputMethodServicesMonitor.getInstance().resetForTesting(); - } - - /** - * This instance holds a set of content monitor singleton objects. - * - * This object is created every time a sub-settings that extends {@code SettingsActivity} - * is created. - */ - public DynamicIndexableContentMonitor() {} - - /** - * Creates and initializes a set of content monitor singleton objects if not yet exist. - * Also starts loading the list of print services. - * mIndex has non-null value after successfully initialized. - * - * @param activity used to get {@link LoaderManager}. - * @param loaderId id for loading print services. - */ - public void register(Activity activity, int loaderId) { - final boolean isUserUnlocked = activity - .getSystemService(UserManager.class) - .isUserUnlocked(); - register(activity, loaderId, FeatureFactory.getFactory(activity) - .getSearchFeatureProvider().getIndexingManager(activity), isUserUnlocked); - } - - /** - * For testing to inject {@link DatabaseIndexingManager} object. - * Also because currently Robolectric doesn't support API 24, we can not test code that calls - * {@link UserManager#isUserUnlocked()}. - */ - @VisibleForTesting - void register(Activity activity, int loaderId, DatabaseIndexingManager indexManager, - boolean isUserUnlocked) { - if (!isUserUnlocked) { - Log.w(TAG, "Skipping content monitoring because user is locked"); - return; - } - final Context context = activity.getApplicationContext(); - mContext = context; - mIndexManager = indexManager; - - PACKAGE_CHANGE_MONITOR.registerMonitor(context); - mHasFeaturePrinting = context.getPackageManager() - .hasSystemFeature(PackageManager.FEATURE_PRINTING); - if (mHasFeaturePrinting) { - activity.getLoaderManager().initLoader(loaderId, null /* args */, this /* callbacks */); - } - - // Watch for input device changes. - InputDevicesMonitor.getInstance().initialize(context, mIndexManager); - - // Start tracking packages. - InputMethodServicesMonitor.getInstance().initialize(context, mIndexManager); - } - - /** - * Aborts loading the list of print services. - * Note that a set of content monitor singletons keep alive while Settings app is running. - * - * @param activity user to get {@link LoaderManager}. - * @param loaderId id for loading print services. - */ - public void unregister(Activity activity, int loaderId) { - if (mIndexManager == null) return; - - PACKAGE_CHANGE_MONITOR.unregisterMonitor(); - if (mHasFeaturePrinting) { - activity.getLoaderManager().destroyLoader(loaderId); - } - } - - @Override - public Loader> onCreateLoader(int id, Bundle args) { - return new PrintServicesLoader( - (PrintManager) mContext.getSystemService(Context.PRINT_SERVICE), mContext, - PrintManager.ALL_SERVICES); - } - - @Override - public void onLoadFinished(Loader> loader, - List services) { - mIndexManager.updateFromClassNameResource(PrintSettingsFragment.class.getName(), - true /* includeInSearchResults */); - } - - @Override - public void onLoaderReset(Loader> loader) { - // nothing to do - } - - // A singleton that monitors input devices changes and updates indexes of physical keyboards. - private static class InputDevicesMonitor implements InputManager.InputDeviceListener { - - // Null if not initialized. - @Nullable private DatabaseIndexingManager mIndexManager; - private InputManager mInputManager; - - private InputDevicesMonitor() {} - - private static class SingletonHolder { - private static final InputDevicesMonitor INSTANCE = new InputDevicesMonitor(); - } - - static InputDevicesMonitor getInstance() { - return SingletonHolder.INSTANCE; - } - - @VisibleForTesting - synchronized void resetForTesting() { - if (mIndexManager != null) { - mInputManager.unregisterInputDeviceListener(this /* listener */); - } - mIndexManager = null; - } - - synchronized void initialize(Context context, DatabaseIndexingManager indexManager) { - if (mIndexManager != null) return; - mIndexManager = indexManager; - mInputManager = (InputManager) context.getSystemService(Context.INPUT_SERVICE); - buildIndex(); - - // Watch for input device changes. - mInputManager.registerInputDeviceListener(this /* listener */, null /* handler */); - } - - private void buildIndex() { - mIndexManager.updateFromClassNameResource(PhysicalKeyboardFragment.class.getName(), - true /* includeInSearchResults */); - } - - @Override - public void onInputDeviceAdded(int deviceId) { - buildIndex(); - } - - @Override - public void onInputDeviceRemoved(int deviceId) { - buildIndex(); - } - - @Override - public void onInputDeviceChanged(int deviceId) { - buildIndex(); - } - } - - // A singleton that monitors package installing, uninstalling, enabling, and disabling. - // Then updates indexes of accessibility services and input methods. - private static class PackageChangeMonitor extends PackageMonitor { - private static final String TAG = PackageChangeMonitor.class.getSimpleName(); - - // Null if not initialized. Guarded by {@link #mLock}. - @Nullable private PackageManager mPackageManager; - private final Object mLock = new Object(); - - public void registerMonitor(Context context) { - synchronized (mLock) { - if (mPackageManager != null) { - return; - } - mPackageManager = context.getPackageManager(); - - // Start tracking packages. Use background thread for monitoring. Note that no need - // to unregister this monitor. This should be alive while Settings app is running. - super.register(context, null /* thread */, UserHandle.CURRENT, false); - } - } - - public void unregisterMonitor() { - synchronized (mLock) { - if (mPackageManager == null) { - return; - } - super.unregister(); - mPackageManager = null; - } - } - - // Covers installed, appeared external storage with the package, upgraded. - @Override - public void onPackageAppeared(String packageName, int reason) { - postPackageAvailable(packageName); - } - - // Covers uninstalled, removed external storage with the package. - @Override - public void onPackageDisappeared(String packageName, int reason) { - postPackageUnavailable(packageName); - } - - // Covers enabled, disabled. - @Override - public void onPackageModified(String packageName) { - try { - final int state = mPackageManager.getApplicationEnabledSetting(packageName); - if (state == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT - || state == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { - postPackageAvailable(packageName); - } else { - postPackageUnavailable(packageName); - } - } catch (IllegalArgumentException e) { - Log.e(TAG, "Package does not exist: " + packageName, e); - } - } - - private void postPackageAvailable(final String packageName) { - getRegisteredHandler().postDelayed(() -> { - InputMethodServicesMonitor.getInstance().onPackageAvailable(packageName); - }, DELAY_PROCESS_PACKAGE_CHANGE); - } - - private void postPackageUnavailable(final String packageName) { - getRegisteredHandler().postDelayed(() -> { - InputMethodServicesMonitor.getInstance().onPackageUnavailable(packageName); - }, DELAY_PROCESS_PACKAGE_CHANGE); - } - } - - // 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 { - - private static final Uri ENABLED_INPUT_METHODS_CONTENT_URI = - Settings.Secure.getUriFor(Settings.Secure.ENABLED_INPUT_METHODS); - - // Null if not initialized. - @Nullable private DatabaseIndexingManager mIndexManager; - private PackageManager mPackageManager; - private ContentResolver mContentResolver; - private final List mInputMethodServices = new ArrayList<>(); - - private InputMethodServicesMonitor() { - // No need for handler because {@link #onChange(boolean,Uri)} is short and quick. - super(null /* handler */); - } - - private static class SingletonHolder { - private static final InputMethodServicesMonitor INSTANCE = - new InputMethodServicesMonitor(); - } - - static InputMethodServicesMonitor getInstance() { - return SingletonHolder.INSTANCE; - } - - @VisibleForTesting - synchronized void resetForTesting() { - if (mIndexManager != null) { - mContentResolver.unregisterContentObserver(this /* observer */); - } - mIndexManager = null; - } - - synchronized void initialize(Context context, DatabaseIndexingManager indexManager) { - final boolean hasFeatureIme = context.getPackageManager() - .hasSystemFeature(PackageManager.FEATURE_INPUT_METHODS); - if (!hasFeatureIme) return; - - if (mIndexManager != null) return; - mIndexManager = indexManager; - mPackageManager = context.getPackageManager(); - mContentResolver = context.getContentResolver(); - mInputMethodServices.clear(); - // Build index of {@link UserDictionary}. - buildIndex(LanguageAndInputSettings.class); - // Build index of IMEs. - buildIndex(VirtualKeyboardFragment.class); - buildIndex(AvailableVirtualKeyboardFragment.class); - - // Cache IME service packages to know when they go away. - final InputMethodManager inputMethodManager = (InputMethodManager) context - .getSystemService(Context.INPUT_METHOD_SERVICE); - for (final InputMethodInfo inputMethod : inputMethodManager.getInputMethodList()) { - ServiceInfo serviceInfo = inputMethod.getServiceInfo(); - if (serviceInfo != null) { - mInputMethodServices.add(serviceInfo.packageName); - } - } - - // TODO: Implements by JobScheduler with TriggerContentUri parameters. - // Watch for related content URIs. - mContentResolver.registerContentObserver(UserDictionary.Words.CONTENT_URI, - true /* notifyForDescendants */, this /* observer */); - // Watch for changing enabled IMEs. - mContentResolver.registerContentObserver(ENABLED_INPUT_METHODS_CONTENT_URI, - false /* notifyForDescendants */, this /* observer */); - } - - private void buildIndex(Class indexClass) { - mIndexManager.updateFromClassNameResource(indexClass.getName(), - true /* includeInSearchResults */); - } - - synchronized void onPackageAvailable(String packageName) { - if (mIndexManager == null) return; - if (mInputMethodServices.contains(packageName)) return; - - final Intent intent = getIMEServiceIntent(packageName); - final List services = mPackageManager - .queryIntentServices(intent, 0 /* flags */); - if (services == null || services.isEmpty()) return; - mInputMethodServices.add(packageName); - buildIndex(VirtualKeyboardFragment.class); - buildIndex(AvailableVirtualKeyboardFragment.class); - } - - synchronized void onPackageUnavailable(String packageName) { - if (mIndexManager == null) return; - if (!mInputMethodServices.remove(packageName)) return; - buildIndex(VirtualKeyboardFragment.class); - buildIndex(AvailableVirtualKeyboardFragment.class); - } - - @Override - public void onChange(boolean selfChange, Uri uri) { - if (ENABLED_INPUT_METHODS_CONTENT_URI.equals(uri)) { - buildIndex(VirtualKeyboardFragment.class); - buildIndex(AvailableVirtualKeyboardFragment.class); - } else if (UserDictionary.Words.CONTENT_URI.equals(uri)) { - buildIndex(LanguageAndInputSettings.class); - } - } - } -} diff --git a/src/com/android/settings/search/InputDeviceResultLoader.java b/src/com/android/settings/search/InputDeviceResultLoader.java new file mode 100644 index 00000000000..61e1ad1671e --- /dev/null +++ b/src/com/android/settings/search/InputDeviceResultLoader.java @@ -0,0 +1,200 @@ +/* + * 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 android.content.Context.INPUT_METHOD_SERVICE; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ServiceInfo; +import android.hardware.input.InputManager; +import android.hardware.input.KeyboardLayout; +import android.support.annotation.VisibleForTesting; +import android.view.InputDevice; +import android.view.inputmethod.InputMethodInfo; +import android.view.inputmethod.InputMethodManager; +import android.view.inputmethod.InputMethodSubtype; + +import com.android.settings.R; +import com.android.settings.dashboard.SiteMapManager; +import com.android.settings.inputmethod.AvailableVirtualKeyboardFragment; +import com.android.settings.inputmethod.PhysicalKeyboardFragment; +import com.android.settings.utils.AsyncLoader; +import com.android.settingslib.inputmethod.InputMethodAndSubtypeUtil; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +/** + * Search result for input devices (physical/virtual keyboard, game controllers, etc) + */ +public class InputDeviceResultLoader extends AsyncLoader> { + private static final int NAME_NO_MATCH = -1; + + @VisibleForTesting + static final String PHYSICAL_KEYBOARD_FRAGMENT = PhysicalKeyboardFragment.class.getName(); + @VisibleForTesting + static final String VIRTUAL_KEYBOARD_FRAGMENT = + AvailableVirtualKeyboardFragment.class.getName(); + + private final SiteMapManager mSiteMapManager; + private final InputManager mInputManager; + private final InputMethodManager mImm; + private final PackageManager mPackageManager; + @VisibleForTesting + final String mQuery; + + private List mPhysicalKeyboardBreadcrumb; + private List mVirtualKeyboardBreadcrumb; + + public InputDeviceResultLoader(Context context, String query, SiteMapManager mapManager) { + super(context); + mQuery = query; + mSiteMapManager = mapManager; + mInputManager = (InputManager) context.getSystemService(Context.INPUT_SERVICE); + mImm = (InputMethodManager) context.getSystemService(INPUT_METHOD_SERVICE); + mPackageManager = context.getPackageManager(); + } + + @Override + protected void onDiscardResult(Set result) { + } + + @Override + public Set loadInBackground() { + final Set results = new HashSet<>(); + results.addAll(buildPhysicalKeyboardSearchResults()); + results.addAll(buildVirtualKeyboardSearchResults()); + return results; + } + + private Set buildPhysicalKeyboardSearchResults() { + final Set results = new HashSet<>(); + final Context context = getContext(); + final String screenTitle = context.getString(R.string.physical_keyboard_title); + + for (final InputDevice device : getPhysicalFullKeyboards()) { + final String deviceName = device.getName(); + final int wordDiff = InstalledAppResultLoader.getWordDifference(deviceName, mQuery); + if (wordDiff == NAME_NO_MATCH) { + continue; + } + final String keyboardLayoutDescriptor = mInputManager + .getCurrentKeyboardLayoutForInputDevice(device.getIdentifier()); + final KeyboardLayout keyboardLayout = (keyboardLayoutDescriptor != null) + ? mInputManager.getKeyboardLayout(keyboardLayoutDescriptor) : null; + final String summary = (keyboardLayout != null) + ? keyboardLayout.toString() + : context.getString(R.string.keyboard_layout_default_label); + final String key = deviceName; + + final Intent intent = DatabaseIndexingUtils.buildSubsettingIntent(context, + PHYSICAL_KEYBOARD_FRAGMENT, key, screenTitle); + results.add(new SearchResult.Builder() + .setTitle(deviceName) + .setPayload(new ResultPayload(intent)) + .setStableId(Objects.hash(PHYSICAL_KEYBOARD_FRAGMENT, key)) + .setSummary(summary) + .setRank(wordDiff) + .addBreadcrumbs(getPhysicalKeyboardBreadCrumb()) + .build()); + } + return results; + } + + private Set buildVirtualKeyboardSearchResults() { + final Set results = new HashSet<>(); + final Context context = getContext(); + final String screenTitle = context.getString(R.string.add_virtual_keyboard); + final List inputMethods = mImm.getInputMethodList(); + for (InputMethodInfo info : inputMethods) { + final String title = info.loadLabel(mPackageManager).toString(); + final String summary = InputMethodAndSubtypeUtil + .getSubtypeLocaleNameListAsSentence(getAllSubtypesOf(info), context, info); + int wordDiff = InstalledAppResultLoader.getWordDifference(title, mQuery); + if (wordDiff == NAME_NO_MATCH) { + wordDiff = InstalledAppResultLoader.getWordDifference(summary, mQuery); + } + if (wordDiff == NAME_NO_MATCH) { + continue; + } + final ServiceInfo serviceInfo = info.getServiceInfo(); + final String key = new ComponentName(serviceInfo.packageName, serviceInfo.name) + .flattenToString(); + final Intent intent = DatabaseIndexingUtils.buildSubsettingIntent(context, + VIRTUAL_KEYBOARD_FRAGMENT, key, screenTitle); + results.add(new SearchResult.Builder() + .setTitle(title) + .setSummary(summary) + .setRank(wordDiff) + .setStableId(Objects.hash(VIRTUAL_KEYBOARD_FRAGMENT, key)) + .addBreadcrumbs(getVirtualKeyboardBreadCrumb()) + .setPayload(new ResultPayload(intent)) + .build()); + } + return results; + } + + private List getPhysicalKeyboardBreadCrumb() { + if (mPhysicalKeyboardBreadcrumb == null || mPhysicalKeyboardBreadcrumb.isEmpty()) { + final Context context = getContext(); + mPhysicalKeyboardBreadcrumb = mSiteMapManager.buildBreadCrumb( + context, PHYSICAL_KEYBOARD_FRAGMENT, + context.getString(R.string.physical_keyboard_title)); + } + return mPhysicalKeyboardBreadcrumb; + } + + + private List getVirtualKeyboardBreadCrumb() { + if (mVirtualKeyboardBreadcrumb == null || mVirtualKeyboardBreadcrumb.isEmpty()) { + final Context context = getContext(); + mVirtualKeyboardBreadcrumb = mSiteMapManager.buildBreadCrumb( + context, VIRTUAL_KEYBOARD_FRAGMENT, + context.getString(R.string.add_virtual_keyboard)); + } + return mVirtualKeyboardBreadcrumb; + } + + private List getPhysicalFullKeyboards() { + final List keyboards = new ArrayList<>(); + final int[] deviceIds = InputDevice.getDeviceIds(); + if (deviceIds != null) { + for (int deviceId : deviceIds) { + final InputDevice device = InputDevice.getDevice(deviceId); + if (device != null && !device.isVirtual() && device.isFullKeyboard()) { + keyboards.add(device); + } + } + } + return keyboards; + } + + private static List getAllSubtypesOf(final InputMethodInfo imi) { + final int subtypeCount = imi.getSubtypeCount(); + final List allSubtypes = new ArrayList<>(subtypeCount); + for (int index = 0; index < subtypeCount; index++) { + allSubtypes.add(imi.getSubtypeAt(index)); + } + return allSubtypes; + } +} diff --git a/src/com/android/settings/search/SearchFeatureProvider.java b/src/com/android/settings/search/SearchFeatureProvider.java index 7e0e08617ba..900cefc3a53 100644 --- a/src/com/android/settings/search/SearchFeatureProvider.java +++ b/src/com/android/settings/search/SearchFeatureProvider.java @@ -48,6 +48,11 @@ public interface SearchFeatureProvider { AccessibilityServiceResultLoader getAccessibilityServiceResultLoader(Context context, String query); + /** + * Returns a new loader to search input devices. + */ + InputDeviceResultLoader getInputDeviceResultLoader(Context context, String query); + /** * Returns a new loader to get all recently saved queries search terms. */ diff --git a/src/com/android/settings/search/SearchFeatureProviderImpl.java b/src/com/android/settings/search/SearchFeatureProviderImpl.java index b90547e5a3b..400cf8fe5f3 100644 --- a/src/com/android/settings/search/SearchFeatureProviderImpl.java +++ b/src/com/android/settings/search/SearchFeatureProviderImpl.java @@ -61,6 +61,11 @@ public class SearchFeatureProviderImpl implements SearchFeatureProvider { getSiteMapManager()); } + @Override + public InputDeviceResultLoader getInputDeviceResultLoader(Context context, String query) { + return new InputDeviceResultLoader(context, cleanQuery(query), getSiteMapManager()); + } + @Override public SavedQueryLoader getSavedQueryLoader(Context context) { return new SavedQueryLoader(context); diff --git a/src/com/android/settings/search/SearchFragment.java b/src/com/android/settings/search/SearchFragment.java index fb89d6e5362..ccc4d61ff73 100644 --- a/src/com/android/settings/search/SearchFragment.java +++ b/src/com/android/settings/search/SearchFragment.java @@ -84,8 +84,10 @@ public class SearchFragment extends InstrumentedFragment implements SearchView.O static final int LOADER_ID_INSTALLED_APPS = 2; @VisibleForTesting static final int LOADER_ID_ACCESSIBILITY_SERVICES = 3; + @VisibleForTesting + static final int LOADER_ID_INPUT_DEVICES = 4; - private static final int NUM_QUERY_LOADERS = 3; + private static final int NUM_QUERY_LOADERS = 4; @VisibleForTesting AtomicInteger mUnfinishedLoadersCount = new AtomicInteger(NUM_QUERY_LOADERS); @@ -284,6 +286,7 @@ public class SearchFragment extends InstrumentedFragment implements SearchView.O loaderManager.destroyLoader(LOADER_ID_DATABASE); loaderManager.destroyLoader(LOADER_ID_INSTALLED_APPS); loaderManager.destroyLoader(LOADER_ID_ACCESSIBILITY_SERVICES); + loaderManager.destroyLoader(LOADER_ID_INPUT_DEVICES); mShowingSavedQuery = true; mSavedQueryController.loadSavedQueries(); mSearchFeatureProvider.hideFeedbackButton(); @@ -314,6 +317,8 @@ public class SearchFragment extends InstrumentedFragment implements SearchView.O return mSearchFeatureProvider.getInstalledAppSearchLoader(activity, mQuery); case LOADER_ID_ACCESSIBILITY_SERVICES: return mSearchFeatureProvider.getAccessibilityServiceResultLoader(activity, mQuery); + case LOADER_ID_INPUT_DEVICES: + return mSearchFeatureProvider.getInputDeviceResultLoader(activity, mQuery); default: return null; } @@ -351,6 +356,8 @@ public class SearchFragment extends InstrumentedFragment implements SearchView.O LOADER_ID_INSTALLED_APPS, null /* args */, this /* callback */); loaderManager.initLoader( LOADER_ID_ACCESSIBILITY_SERVICES, null /* args */, this /* callback */); + loaderManager.initLoader( + LOADER_ID_INPUT_DEVICES, null /* args */, this /* callback */); } requery(); @@ -392,6 +399,8 @@ public class SearchFragment extends InstrumentedFragment implements SearchView.O loaderManager.restartLoader(LOADER_ID_INSTALLED_APPS, null /* args */, this /* callback */); loaderManager.restartLoader(LOADER_ID_ACCESSIBILITY_SERVICES, null /* args */, this /* callback */); + loaderManager.restartLoader(LOADER_ID_INPUT_DEVICES, null /* args */, + this /* callback */); } public String getQuery() { diff --git a/src/com/android/settings/search/SearchResultsAdapter.java b/src/com/android/settings/search/SearchResultsAdapter.java index 6c58a0d039a..7b886a46cd0 100644 --- a/src/com/android/settings/search/SearchResultsAdapter.java +++ b/src/com/android/settings/search/SearchResultsAdapter.java @@ -57,7 +57,9 @@ public class SearchResultsAdapter extends RecyclerView.Adapter @VisibleForTesting static final String APP_RESULTS_LOADER_KEY = InstalledAppResultLoader.class.getName(); @VisibleForTesting - static final String ACCESSIBLITY_LOADER_KEY = AccessibilityServiceResultLoader.class.getName(); + static final String ACCESSIBILITY_LOADER_KEY = AccessibilityServiceResultLoader.class.getName(); + @VisibleForTesting + static final String INPUT_DEVICE_LOADER_KEY = InputDeviceResultLoader.class.getName(); @VisibleForTesting static final int MSG_RANKING_TIMED_OUT = 1; @@ -265,17 +267,21 @@ public class SearchResultsAdapter extends RecyclerView.Adapter List installedAppResults = getSortedLoadedResults(APP_RESULTS_LOADER_KEY); List accessibilityResults = - getSortedLoadedResults(ACCESSIBLITY_LOADER_KEY); + getSortedLoadedResults(ACCESSIBILITY_LOADER_KEY); + List inputDeviceResults = + getSortedLoadedResults(INPUT_DEVICE_LOADER_KEY); int dbSize = databaseResults.size(); int appSize = installedAppResults.size(); int a11ySize = accessibilityResults.size(); - + int inputDeviceSize = inputDeviceResults.size(); int dbIndex = 0; int appIndex = 0; int a11yIndex = 0; + int inputDeviceIndex = 0; int rank = SearchResult.TOP_RANK; + // TODO: We need a helper method to do k-way merge. mStaticallyRankedSearchResults.clear(); while (rank <= SearchResult.BOTTOM_RANK) { while ((dbIndex < dbSize) && (databaseResults.get(dbIndex).rank == rank)) { @@ -287,6 +293,10 @@ public class SearchResultsAdapter extends RecyclerView.Adapter while ((a11yIndex < a11ySize) && (accessibilityResults.get(a11yIndex).rank == rank)) { mStaticallyRankedSearchResults.add(accessibilityResults.get(a11yIndex++)); } + while (inputDeviceIndex < inputDeviceSize + && inputDeviceResults.get(inputDeviceIndex).rank == rank) { + mStaticallyRankedSearchResults.add(inputDeviceResults.get(inputDeviceIndex++)); + } rank++; } @@ -299,6 +309,9 @@ public class SearchResultsAdapter extends RecyclerView.Adapter while(a11yIndex < a11ySize) { mStaticallyRankedSearchResults.add(accessibilityResults.get(a11yIndex++)); } + while (inputDeviceIndex < inputDeviceSize) { + mStaticallyRankedSearchResults.add(inputDeviceResults.get(inputDeviceIndex++)); + } } private void updateSearchResults() { @@ -332,12 +345,16 @@ public class SearchResultsAdapter extends RecyclerView.Adapter List installedAppResults = getSortedLoadedResults(APP_RESULTS_LOADER_KEY); List accessibilityResults = - getSortedLoadedResults(ACCESSIBLITY_LOADER_KEY); + getSortedLoadedResults(ACCESSIBILITY_LOADER_KEY); + List inputDeviceResults = + getSortedLoadedResults(INPUT_DEVICE_LOADER_KEY); int dbSize = databaseResults.size(); int appSize = installedAppResults.size(); int a11ySize = accessibilityResults.size(); + int inputDeviceSize = inputDeviceResults.size(); - final List asyncRankingResults = new ArrayList<>(dbSize + appSize + a11ySize); + final List asyncRankingResults = new ArrayList<>( + dbSize + appSize + a11ySize + inputDeviceSize); TreeSet dbResultsSortedByScores = new TreeSet<>( new Comparator() { @Override @@ -358,13 +375,13 @@ public class SearchResultsAdapter extends RecyclerView.Adapter // Other results are not ranked by async ranking and appended at the end of the list. asyncRankingResults.addAll(installedAppResults); asyncRankingResults.addAll(accessibilityResults); + asyncRankingResults.addAll(inputDeviceResults); return asyncRankingResults; } @VisibleForTesting Set getUnsortedLoadedResults(String loaderKey) { - return mResultsMap.containsKey(loaderKey) ? - mResultsMap.get(loaderKey) : new HashSet(); + return mResultsMap.containsKey(loaderKey) ? mResultsMap.get(loaderKey) : new HashSet<>(); } @VisibleForTesting diff --git a/tests/robotests/src/com/android/settings/SetupChooseLockPatternTest.java b/tests/robotests/src/com/android/settings/SetupChooseLockPatternTest.java index 78bc7d14768..69a13517951 100644 --- a/tests/robotests/src/com/android/settings/SetupChooseLockPatternTest.java +++ b/tests/robotests/src/com/android/settings/SetupChooseLockPatternTest.java @@ -30,7 +30,6 @@ import com.android.settings.password.ChooseLockPattern.IntentBuilder; import com.android.settings.password.SetupChooseLockPattern; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.SettingsShadowResources; -import com.android.settings.testutils.shadow.ShadowDynamicIndexableContentMonitor; import com.android.settings.testutils.shadow.ShadowEventLogWriter; import com.android.settings.testutils.shadow.ShadowUtils; @@ -49,7 +48,6 @@ import org.robolectric.res.builder.RobolectricPackageManager.ComponentState; shadows = { SettingsShadowResources.class, SettingsShadowResources.SettingsShadowTheme.class, - ShadowDynamicIndexableContentMonitor.class, ShadowEventLogWriter.class, ShadowUtils.class }) diff --git a/tests/robotests/src/com/android/settings/applications/ManageApplicationsTest.java b/tests/robotests/src/com/android/settings/applications/ManageApplicationsTest.java index 92aa675c00d..8ed72848457 100644 --- a/tests/robotests/src/com/android/settings/applications/ManageApplicationsTest.java +++ b/tests/robotests/src/com/android/settings/applications/ManageApplicationsTest.java @@ -16,6 +16,17 @@ package com.android.settings.applications; +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.eq; +import static org.mockito.Mockito.doNothing; +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.app.Activity; import android.content.Context; import android.content.pm.ApplicationInfo; @@ -35,7 +46,6 @@ import com.android.settings.TestConfig; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.SettingsShadowResources; import com.android.settings.testutils.shadow.SettingsShadowResources.SettingsShadowTheme; -import com.android.settings.testutils.shadow.ShadowDynamicIndexableContentMonitor; import com.android.settings.testutils.shadow.ShadowEventLogWriter; import com.android.settings.widget.LoadingViewController; import com.android.settingslib.applications.ApplicationsState; @@ -53,17 +63,6 @@ import org.robolectric.util.ReflectionHelpers; import java.util.ArrayList; -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.eq; -import static org.mockito.Mockito.doNothing; -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; - /** * Tests for {@link ManageApplications}. */ @@ -74,7 +73,6 @@ import static org.mockito.Mockito.when; shadows = { SettingsShadowResources.class, SettingsShadowTheme.class, - ShadowDynamicIndexableContentMonitor.class, ShadowEventLogWriter.class }) public class ManageApplicationsTest { diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardAdapterTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardAdapterTest.java index 8a8a13d02be..6b56c291324 100644 --- a/tests/robotests/src/com/android/settings/dashboard/DashboardAdapterTest.java +++ b/tests/robotests/src/com/android/settings/dashboard/DashboardAdapterTest.java @@ -15,6 +15,19 @@ */ package com.android.settings.dashboard; +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -38,7 +51,6 @@ import com.android.settings.dashboard.suggestions.SuggestionAdapter; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.SettingsShadowResources; -import com.android.settings.testutils.shadow.ShadowDynamicIndexableContentMonitor; import com.android.settingslib.drawer.DashboardCategory; import com.android.settingslib.drawer.Tile; @@ -56,26 +68,12 @@ import org.robolectric.annotation.Config; import java.util.ArrayList; import java.util.List; -import static com.google.common.truth.Truth.assertThat; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - @RunWith(SettingsRobolectricTestRunner.class) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION, shadows = { SettingsShadowResources.class, SettingsShadowResources.SettingsShadowTheme.class, - ShadowDynamicIndexableContentMonitor.class }) public class DashboardAdapterTest { diff --git a/tests/robotests/src/com/android/settings/fingerprint/FingerprintEnrollFindSensorTest.java b/tests/robotests/src/com/android/settings/fingerprint/FingerprintEnrollFindSensorTest.java index 344914a4941..ad52bf6026e 100644 --- a/tests/robotests/src/com/android/settings/fingerprint/FingerprintEnrollFindSensorTest.java +++ b/tests/robotests/src/com/android/settings/fingerprint/FingerprintEnrollFindSensorTest.java @@ -36,7 +36,6 @@ import com.android.settings.password.ChooseLockSettingsHelper; import com.android.settings.password.IFingerprintManager; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.SettingsShadowResources; -import com.android.settings.testutils.shadow.ShadowDynamicIndexableContentMonitor; import com.android.settings.testutils.shadow.ShadowEventLogWriter; import com.android.settings.testutils.shadow.ShadowUtils; @@ -61,7 +60,6 @@ import org.robolectric.shadows.ShadowActivity.IntentForResult; shadows = { SettingsShadowResources.class, SettingsShadowResources.SettingsShadowTheme.class, - ShadowDynamicIndexableContentMonitor.class, ShadowEventLogWriter.class, ShadowUtils.class }) diff --git a/tests/robotests/src/com/android/settings/fingerprint/SetupFingerprintEnrollFindSensorTest.java b/tests/robotests/src/com/android/settings/fingerprint/SetupFingerprintEnrollFindSensorTest.java index f1b7ee0a231..3b678519064 100644 --- a/tests/robotests/src/com/android/settings/fingerprint/SetupFingerprintEnrollFindSensorTest.java +++ b/tests/robotests/src/com/android/settings/fingerprint/SetupFingerprintEnrollFindSensorTest.java @@ -30,7 +30,6 @@ import com.android.settings.password.ChooseLockSettingsHelper; import com.android.settings.password.IFingerprintManager; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.SettingsShadowResources; -import com.android.settings.testutils.shadow.ShadowDynamicIndexableContentMonitor; import com.android.settings.testutils.shadow.ShadowEventLogWriter; import com.android.settings.testutils.shadow.ShadowUtils; @@ -53,7 +52,6 @@ import org.robolectric.shadows.ShadowAlertDialog; shadows = { SettingsShadowResources.class, SettingsShadowResources.SettingsShadowTheme.class, - ShadowDynamicIndexableContentMonitor.class, ShadowEventLogWriter.class, ShadowUtils.class }) diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java index 013d379b8b1..e434bb327fd 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java @@ -17,6 +17,15 @@ package com.android.settings.fuelgauge; +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import android.app.Activity; import android.content.Context; import android.content.Intent; @@ -27,11 +36,10 @@ import android.support.v7.widget.RecyclerView; import android.widget.TextView; import com.android.settings.R; -import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; import com.android.settings.applications.LayoutPreference; +import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.SettingsShadowResources; -import com.android.settings.testutils.shadow.ShadowDynamicIndexableContentMonitor; import com.android.settings.testutils.shadow.ShadowEntityHeaderController; import com.android.settings.widget.EntityHeaderController; import com.android.settingslib.core.lifecycle.Lifecycle; @@ -45,23 +53,12 @@ import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.nullable; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.doReturn; -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, shadows = { SettingsShadowResources.class, SettingsShadowResources.SettingsShadowTheme.class, - ShadowDynamicIndexableContentMonitor.class, ShadowEntityHeaderController.class }) public class BatteryHeaderPreferenceControllerTest { diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryMeterViewTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryMeterViewTest.java index e3a94d24a42..3a1fad0fcbf 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryMeterViewTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryMeterViewTest.java @@ -16,15 +16,17 @@ package com.android.settings.fuelgauge; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; import android.content.Context; import android.graphics.ColorFilter; -import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; +import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.SettingsShadowResources; import com.android.settings.testutils.shadow.SettingsShadowResources.SettingsShadowTheme; -import com.android.settings.testutils.shadow.ShadowDynamicIndexableContentMonitor; import org.junit.Before; import org.junit.Test; @@ -34,10 +36,6 @@ import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; - @RunWith(SettingsRobolectricTestRunner.class) // TODO: Consider making the shadow class set global using a robolectric.properties file. @Config(manifest = TestConfig.MANIFEST_PATH, @@ -45,7 +43,6 @@ import static org.mockito.Mockito.verify; shadows = { SettingsShadowResources.class, SettingsShadowTheme.class, - ShadowDynamicIndexableContentMonitor.class }) public class BatteryMeterViewTest { private static final int BATTERY_LEVEL = 100; diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java index 83e630dfa79..48a48b1abce 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java @@ -18,9 +18,7 @@ package com.android.settings.fuelgauge; import static com.android.settings.fuelgauge.PowerUsageSummary.MENU_ADDITIONAL_BATTERY_INFO; import static com.android.settings.fuelgauge.PowerUsageSummary.MENU_HIGH_POWER_APPS; import static com.android.settings.fuelgauge.PowerUsageSummary.MENU_TOGGLE_APPS; - 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.anyLong; @@ -34,8 +32,6 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import java.util.List; - import android.app.LoaderManager; import android.content.ContentResolver; import android.content.Context; @@ -68,7 +64,6 @@ import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.XmlTestUtils; import com.android.settings.testutils.shadow.SettingsShadowResources; -import com.android.settings.testutils.shadow.ShadowDynamicIndexableContentMonitor; import com.android.settingslib.core.AbstractPreferenceController; import org.junit.Before; @@ -95,7 +90,6 @@ import java.util.List; shadows = { SettingsShadowResources.class, SettingsShadowResources.SettingsShadowTheme.class, - ShadowDynamicIndexableContentMonitor.class }) public class PowerUsageSummaryTest { private static final String[] PACKAGE_NAMES = {"com.app1", "com.app2"}; diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java index 5fa731eddc1..b8f06793ac3 100644 --- a/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java +++ b/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java @@ -31,7 +31,6 @@ import com.android.settings.password.ChooseLockPassword.ChooseLockPasswordFragme import com.android.settings.password.ChooseLockPassword.IntentBuilder; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.SettingsShadowResources; -import com.android.settings.testutils.shadow.ShadowDynamicIndexableContentMonitor; import com.android.settings.testutils.shadow.ShadowEventLogWriter; import com.android.settings.testutils.shadow.ShadowUtils; import com.android.setupwizardlib.GlifLayout; @@ -52,7 +51,6 @@ import org.robolectric.shadows.ShadowDrawable; shadows = { SettingsShadowResources.class, SettingsShadowResources.SettingsShadowTheme.class, - ShadowDynamicIndexableContentMonitor.class, ShadowEventLogWriter.class, ShadowUtils.class }) diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockPatternTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockPatternTest.java index b2380496ae1..c74448b5dd9 100644 --- a/tests/robotests/src/com/android/settings/password/ChooseLockPatternTest.java +++ b/tests/robotests/src/com/android/settings/password/ChooseLockPatternTest.java @@ -29,7 +29,6 @@ import com.android.settings.password.ChooseLockPattern.ChooseLockPatternFragment import com.android.settings.password.ChooseLockPattern.IntentBuilder; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.SettingsShadowResources; -import com.android.settings.testutils.shadow.ShadowDynamicIndexableContentMonitor; import com.android.settings.testutils.shadow.ShadowEventLogWriter; import com.android.settings.testutils.shadow.ShadowUtils; import com.android.setupwizardlib.GlifLayout; @@ -48,7 +47,6 @@ import org.robolectric.shadows.ShadowDrawable; shadows = { SettingsShadowResources.class, SettingsShadowResources.SettingsShadowTheme.class, - ShadowDynamicIndexableContentMonitor.class, ShadowEventLogWriter.class, ShadowUtils.class }) diff --git a/tests/robotests/src/com/android/settings/password/SetupChooseLockPasswordTest.java b/tests/robotests/src/com/android/settings/password/SetupChooseLockPasswordTest.java index 39a0fb66663..1195a2c2ecd 100644 --- a/tests/robotests/src/com/android/settings/password/SetupChooseLockPasswordTest.java +++ b/tests/robotests/src/com/android/settings/password/SetupChooseLockPasswordTest.java @@ -34,7 +34,6 @@ import com.android.settings.password.ChooseLockPassword.IntentBuilder; import com.android.settings.password.SetupChooseLockPassword.SetupChooseLockPasswordFragment; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.SettingsShadowResources; -import com.android.settings.testutils.shadow.ShadowDynamicIndexableContentMonitor; import com.android.settings.testutils.shadow.ShadowEventLogWriter; import com.android.settings.testutils.shadow.ShadowUtils; @@ -62,7 +61,6 @@ import java.util.List; shadows = { SettingsShadowResources.class, SettingsShadowResources.SettingsShadowTheme.class, - ShadowDynamicIndexableContentMonitor.class, ShadowEventLogWriter.class, ShadowUtils.class }) diff --git a/tests/robotests/src/com/android/settings/password/SetupSkipDialogTest.java b/tests/robotests/src/com/android/settings/password/SetupSkipDialogTest.java index 639349dafd9..0e6f28a5686 100644 --- a/tests/robotests/src/com/android/settings/password/SetupSkipDialogTest.java +++ b/tests/robotests/src/com/android/settings/password/SetupSkipDialogTest.java @@ -27,7 +27,6 @@ import com.android.settings.R; import com.android.settings.TestConfig; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.SettingsShadowResources; -import com.android.settings.testutils.shadow.ShadowDynamicIndexableContentMonitor; import com.android.settings.testutils.shadow.ShadowEventLogWriter; import com.android.settings.testutils.shadow.ShadowUtils; @@ -40,13 +39,11 @@ import org.robolectric.annotation.Config; import org.robolectric.shadows.ShadowAlertDialog; @RunWith(SettingsRobolectricTestRunner.class) -@Config( - manifest = TestConfig.MANIFEST_PATH, +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION, shadows = { SettingsShadowResources.class, SettingsShadowResources.SettingsShadowTheme.class, - ShadowDynamicIndexableContentMonitor.class, ShadowEventLogWriter.class, ShadowUtils.class }) diff --git a/tests/robotests/src/com/android/settings/search/DynamicIndexableContentMonitorTest.java b/tests/robotests/src/com/android/settings/search/DynamicIndexableContentMonitorTest.java deleted file mode 100644 index 26c89d5e9b8..00000000000 --- a/tests/robotests/src/com/android/settings/search/DynamicIndexableContentMonitorTest.java +++ /dev/null @@ -1,563 +0,0 @@ -/* - * Copyright (C) 2016 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.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; -import android.app.LoaderManager; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.Loader; -import android.content.pm.ActivityInfo; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.content.pm.ServiceInfo; -import android.database.ContentObserver; -import android.hardware.input.InputManager; -import android.net.Uri; -import android.os.Bundle; -import android.print.PrintManager; -import android.print.PrintServicesLoader; -import android.printservice.PrintServiceInfo; -import android.provider.Settings; -import android.provider.UserDictionary; -import android.view.inputmethod.InputMethodInfo; - -import com.android.internal.content.PackageMonitor; -import com.android.settings.TestConfig; -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; -import com.android.settings.testutils.shadow.ShadowInputMethodManagerWithMethodList; -import com.android.settings.testutils.shadow.ShadowPackageMonitor; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.robolectric.Robolectric; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; -import org.robolectric.internal.ShadowExtractor; -import org.robolectric.res.builder.RobolectricPackageManager; -import org.robolectric.shadows.ShadowAccessibilityManager; -import org.robolectric.shadows.ShadowApplication; -import org.robolectric.shadows.ShadowContentResolver; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -@RunWith(SettingsRobolectricTestRunner.class) -@Config( - manifest = TestConfig.MANIFEST_PATH, - sdk = TestConfig.SDK_VERSION, - shadows = { - ShadowActivityWithLoadManager.class, - ShadowContextImplWithRegisterReceiver.class, - ShadowInputManager.class, - ShadowInputMethodManagerWithMethodList.class, - ShadowPackageMonitor.class, - } -) -public class DynamicIndexableContentMonitorTest { - - private static final int LOADER_ID = 1234; - private static final String A11Y_PACKAGE_1 = "a11y-1"; - private static final String A11Y_PACKAGE_2 = "a11y-2"; - private static final String IME_PACKAGE_1 = "ime-1"; - private static final String IME_PACKAGE_2 = "ime-2"; - - @Mock - private LoaderManager mLoaderManager; - @Mock - private DatabaseIndexingManager mIndexManager; - - private Activity mActivity; - private InputManager mInputManager; - - private ShadowContextImplWithRegisterReceiver mShadowContextImpl; - private ShadowActivityWithLoadManager mShadowActivity; - private ShadowAccessibilityManager mShadowAccessibilityManager; - private ShadowInputMethodManagerWithMethodList mShadowInputMethodManager; - private RobolectricPackageManager mRobolectricPackageManager; - - private final DynamicIndexableContentMonitor mMonitor = new DynamicIndexableContentMonitor(); - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - mActivity = Robolectric.buildActivity(Activity.class).get(); - mInputManager = InputManager.getInstance(); - - // Robolectric shadows. - mShadowContextImpl = (ShadowContextImplWithRegisterReceiver) ShadowExtractor.extract( - ((Application) ShadowApplication.getInstance().getApplicationContext()) - .getBaseContext()); - mShadowActivity = (ShadowActivityWithLoadManager) ShadowExtractor.extract(mActivity); - mShadowAccessibilityManager = (ShadowAccessibilityManager) ShadowExtractor.extract( - mActivity.getSystemService(Context.ACCESSIBILITY_SERVICE)); - mShadowInputMethodManager = (ShadowInputMethodManagerWithMethodList) ShadowExtractor - .extract(mActivity.getSystemService(Context.INPUT_METHOD_SERVICE)); - mRobolectricPackageManager = RuntimeEnvironment.getRobolectricPackageManager(); - - // Setup shadows. - mShadowContextImpl.setSystemService(Context.PRINT_SERVICE, mock(PrintManager.class)); - mShadowContextImpl.setSystemService(Context.INPUT_SERVICE, mInputManager); - mShadowActivity.setLoaderManager(mLoaderManager); - mShadowAccessibilityManager.setInstalledAccessibilityServiceList(Collections.emptyList()); - mShadowInputMethodManager.setInputMethodList(Collections.emptyList()); - mRobolectricPackageManager.setSystemFeature(PackageManager.FEATURE_PRINTING, true); - mRobolectricPackageManager.setSystemFeature(PackageManager.FEATURE_INPUT_METHODS, true); - } - - @After - public void shutDown() { - mMonitor.unregister(mActivity, LOADER_ID); - // BroadcastReceiver must be unregistered. - assertThat(extractPackageMonitor()).isNull(); - - DynamicIndexableContentMonitor.resetForTesting(); - mRobolectricPackageManager.reset(); - - DatabaseTestUtils.clearDb(mActivity); - } - - @Test - public void testLockedUser() { - mMonitor.register(mActivity, LOADER_ID, mIndexManager, false /* isUserUnlocked */); - - // No loader procedure happens. - verify(mLoaderManager, never()).initLoader( - anyInt(), any(Bundle.class), any(LoaderManager.LoaderCallbacks.class)); - // No indexing happens. - verify(mIndexManager, never()).updateFromClassNameResource( - anyString(), anyBoolean()); - - mMonitor.unregister(mActivity, LOADER_ID); - - // No destroy loader should happen. - verify(mLoaderManager, never()).destroyLoader(anyInt()); - } - - @Test - public void testWithNoPrintingFeature() { - mRobolectricPackageManager.setSystemFeature(PackageManager.FEATURE_PRINTING, false); - - mMonitor.register(mActivity, LOADER_ID, mIndexManager, true /* isUserUnlocked */); - - // No loader procedure happens. - verify(mLoaderManager, never()).initLoader( - anyInt(), any(Bundle.class), any(LoaderManager.LoaderCallbacks.class)); - verifyNoIndexing(PrintSettingsFragment.class); - - mMonitor.unregister(mActivity, LOADER_ID); - - // No destroy loader should happen. - verify(mLoaderManager, never()).destroyLoader(anyInt()); - // BroadcastReceiver must be unregistered. - assertThat(extractPackageMonitor()).isNull(); - - // To suppress spurious test fail in {@link #shutDown()}. - mMonitor.register(mActivity, LOADER_ID, mIndexManager, true /* isUserUnlocked */); - } - - @Test - public void testPrinterServiceIndex() { - mMonitor.register(mActivity, LOADER_ID, mIndexManager, true /* isUserUnlocked */); - - // Loader procedure happens. - verify(mLoaderManager, only()).initLoader(LOADER_ID, null, mMonitor); - - // Loading print services happens. - final Loader> loader = - mMonitor.onCreateLoader(LOADER_ID, null /* args */); - assertThat(loader).isInstanceOf(PrintServicesLoader.class); - verifyNoIndexing(PrintSettingsFragment.class); - - mMonitor.onLoadFinished(loader, Collections.emptyList()); - - verifyIncrementalIndexing(PrintSettingsFragment.class); - } - - @Test - public void testInputDevicesMonitor() { - mMonitor.register(mActivity, LOADER_ID, mIndexManager, true /* isUserUnlocked */); - - // Rebuild indexing should happen. - verifyIncrementalIndexing(PhysicalKeyboardFragment.class); - // Input monitor should be registered to InputManager. - final InputManager.InputDeviceListener listener = extactInputDeviceListener(); - assertThat(listener).isNotNull(); - - /* - * Nothing happens on successive register calls. - */ - mMonitor.unregister(mActivity, LOADER_ID); - reset(mIndexManager); - - mMonitor.register(mActivity, LOADER_ID, mIndexManager, true /* isUserUnlocked */); - - verifyNoIndexing(PhysicalKeyboardFragment.class); - assertThat(extactInputDeviceListener()).isEqualTo(listener); - - /* - * A device is added. - */ - reset(mIndexManager); - - listener.onInputDeviceAdded(1 /* deviceId */); - - verifyIncrementalIndexing(PhysicalKeyboardFragment.class); - - /* - * A device is removed. - */ - reset(mIndexManager); - - listener.onInputDeviceRemoved(2 /* deviceId */); - - verifyIncrementalIndexing(PhysicalKeyboardFragment.class); - - /* - * A device is changed. - */ - reset(mIndexManager); - - listener.onInputDeviceChanged(3 /* deviceId */); - - verifyIncrementalIndexing(PhysicalKeyboardFragment.class); - } - - @Test - public void testInputMethodServicesMonitor() throws Exception { - mMonitor.register(mActivity, LOADER_ID, mIndexManager, true /* isUserUnlocked */); - - verifyIncrementalIndexing(VirtualKeyboardFragment.class); - verifyIncrementalIndexing(AvailableVirtualKeyboardFragment.class); - - final Uri enabledInputMethodsContentUri = Settings.Secure.getUriFor( - Settings.Secure.ENABLED_INPUT_METHODS); - // Content observer should be registered. - final ContentObserver observer = extractContentObserver(enabledInputMethodsContentUri); - assertThat(observer).isNotNull(); - - /* - * When an input method service package is installed, incremental indexing happen. - */ - reset(mIndexManager); - - installInputMethodService(IME_PACKAGE_1); - - verifyIncrementalIndexing(VirtualKeyboardFragment.class); - verifyIncrementalIndexing(AvailableVirtualKeyboardFragment.class); - - /* - * When another input method service package is installed, incremental indexing happens. - */ - reset(mIndexManager); - - installInputMethodService(IME_PACKAGE_2); - - verifyIncrementalIndexing(VirtualKeyboardFragment.class); - verifyIncrementalIndexing(AvailableVirtualKeyboardFragment.class); - - /* - * When an input method service is disabled, rebuild indexing happens. - */ - reset(mIndexManager); - - disableInstalledPackage(IME_PACKAGE_1); - - verifyIncrementalIndexing(VirtualKeyboardFragment.class); - verifyIncrementalIndexing(AvailableVirtualKeyboardFragment.class); - - /* - * When an input method service is enabled, incremental indexing happens. - */ - reset(mIndexManager); - - enableInstalledPackage(IME_PACKAGE_1); - - verifyIncrementalIndexing(VirtualKeyboardFragment.class); - verifyIncrementalIndexing(AvailableVirtualKeyboardFragment.class); - - /* - * When an input method service package is uninstalled, rebuild indexing happens. - */ - reset(mIndexManager); - - uninstallInputMethodService(IME_PACKAGE_1); - - verifyIncrementalIndexing(VirtualKeyboardFragment.class); - verifyIncrementalIndexing(AvailableVirtualKeyboardFragment.class); - - /* - * When an accessibility service package is installed, nothing happens. - */ - reset(mIndexManager); - - installAccessibilityService(A11Y_PACKAGE_1); - - verifyNoIndexing(VirtualKeyboardFragment.class); - verifyNoIndexing(AvailableVirtualKeyboardFragment.class); - - /* - * When enabled IMEs list is changed, rebuild indexing happens. - */ - reset(mIndexManager); - - observer.onChange(false /* selfChange */, enabledInputMethodsContentUri); - - verifyIncrementalIndexing(VirtualKeyboardFragment.class); - verifyIncrementalIndexing(AvailableVirtualKeyboardFragment.class); - } - - @Test - public void testUserDictionaryChangeMonitor() throws Exception { - mMonitor.register(mActivity, LOADER_ID, mIndexManager, true /* isUserUnlocked */); - - // Content observer should be registered. - final ContentObserver observer = extractContentObserver(UserDictionary.Words.CONTENT_URI); - assertThat(observer).isNotNull(); - - verifyIncrementalIndexing(LanguageAndInputSettings.class); - - /* - * When user dictionary content is changed, rebuild indexing happens. - */ - reset(mIndexManager); - - observer.onChange(false /* selfChange */, UserDictionary.Words.CONTENT_URI); - - verifyIncrementalIndexing(LanguageAndInputSettings.class); - } - - /* - * Verification helpers. - */ - - private void verifyNoIndexing(Class indexingClass) { - verify(mIndexManager, never()).updateFromClassNameResource(eq(indexingClass.getName()), - anyBoolean()); - } - - private void verifyIncrementalIndexing(Class indexingClass) { - verify(mIndexManager, times(1)).updateFromClassNameResource(indexingClass.getName(), - true /* includeInSearchResults */); - verify(mIndexManager, never()).updateFromClassNameResource(indexingClass.getName(), - false /* includeInSearchResults */); - } - - /* - * Testing helper methods. - */ - - private InputManager.InputDeviceListener extactInputDeviceListener() { - List listeners = ((ShadowInputManager) ShadowExtractor - .extract(mInputManager)) - .getRegisteredInputDeviceListeners(); - InputManager.InputDeviceListener inputDeviceListener = null; - for (InputManager.InputDeviceListener listener : listeners) { - if (isUnderTest(listener)) { - if (inputDeviceListener != null) { - assertThat(listener).isEqualTo(inputDeviceListener); - } else { - inputDeviceListener = listener; - } - } - } - return inputDeviceListener; - } - - private PackageMonitor extractPackageMonitor() { - List receivers = ShadowApplication.getInstance() - .getRegisteredReceivers(); - PackageMonitor packageMonitor = null; - for (ShadowApplication.Wrapper wrapper : receivers) { - BroadcastReceiver receiver = wrapper.getBroadcastReceiver(); - if (isUnderTest(receiver) && receiver instanceof PackageMonitor) { - if (packageMonitor != null) { - assertThat(receiver).isEqualTo(packageMonitor); - } else { - packageMonitor = (PackageMonitor) receiver; - } - } - } - return packageMonitor; - } - - private ContentObserver extractContentObserver(Uri uri) { - ShadowContentResolver contentResolver = (ShadowContentResolver) ShadowExtractor - .extract(mActivity.getContentResolver()); - Collection observers = contentResolver.getContentObservers(uri); - ContentObserver contentObserver = null; - for (ContentObserver observer : observers) { - if (isUnderTest(observer)) { - if (contentObserver != null) { - assertThat(observer).isEqualTo(contentObserver); - } else { - contentObserver = observer; - } - } - } - return contentObserver; - } - - private void enableInstalledPackage(String packageName) { - ((PackageManager) mRobolectricPackageManager).setApplicationEnabledSetting( - packageName, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, 0 /* flags */); - extractPackageMonitor().onPackageModified(packageName); - Robolectric.flushBackgroundThreadScheduler(); - } - - private void disableInstalledPackage(String packageName) { - ((PackageManager) mRobolectricPackageManager).setApplicationEnabledSetting( - packageName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 0 /* flags */); - extractPackageMonitor().onPackageModified(packageName); - Robolectric.flushBackgroundThreadScheduler(); - } - - private void installAccessibilityService(String packageName) throws Exception { - final AccessibilityServiceInfo serviceToAdd = buildAccessibilityServiceInfo(packageName); - - final List services = new ArrayList<>(); - services.addAll(mShadowAccessibilityManager.getInstalledAccessibilityServiceList()); - services.add(serviceToAdd); - mShadowAccessibilityManager.setInstalledAccessibilityServiceList(services); - - final Intent intent = DynamicIndexableContentMonitor - .getAccessibilityServiceIntent(packageName); - mRobolectricPackageManager.addResolveInfoForIntent(intent, serviceToAdd.getResolveInfo()); - mRobolectricPackageManager.addPackage(packageName); - - extractPackageMonitor() - .onPackageAppeared(packageName, PackageMonitor.PACKAGE_PERMANENT_CHANGE); - Robolectric.flushBackgroundThreadScheduler(); - } - - private void uninstallAccessibilityService(String packageName) throws Exception { - final AccessibilityServiceInfo serviceToRemove = buildAccessibilityServiceInfo(packageName); - - final List services = new ArrayList<>(); - services.addAll(mShadowAccessibilityManager.getInstalledAccessibilityServiceList()); - services.remove(serviceToRemove); - mShadowAccessibilityManager.setInstalledAccessibilityServiceList(services); - - final Intent intent = DynamicIndexableContentMonitor - .getAccessibilityServiceIntent(packageName); - mRobolectricPackageManager.removeResolveInfosForIntent(intent, packageName); - mRobolectricPackageManager.removePackage(packageName); - - extractPackageMonitor() - .onPackageDisappeared(packageName, PackageMonitor.PACKAGE_PERMANENT_CHANGE); - Robolectric.flushBackgroundThreadScheduler(); - } - - private void installInputMethodService(String packageName) throws Exception { - final ResolveInfo resolveInfoToAdd = buildResolveInfo(packageName, "imeService"); - final InputMethodInfo serviceToAdd = buildInputMethodInfo(resolveInfoToAdd); - - final List services = new ArrayList<>(); - services.addAll(mShadowInputMethodManager.getInputMethodList()); - services.add(serviceToAdd); - mShadowInputMethodManager.setInputMethodList(services); - - final Intent intent = DynamicIndexableContentMonitor.getIMEServiceIntent(packageName); - mRobolectricPackageManager.addResolveInfoForIntent(intent, resolveInfoToAdd); - mRobolectricPackageManager.addPackage(packageName); - - extractPackageMonitor() - .onPackageAppeared(packageName, PackageMonitor.PACKAGE_PERMANENT_CHANGE); - Robolectric.flushBackgroundThreadScheduler(); - } - - private void uninstallInputMethodService(String packageName) throws Exception { - final ResolveInfo resolveInfoToRemove = buildResolveInfo(packageName, "imeService"); - final InputMethodInfo serviceToRemove = buildInputMethodInfo(resolveInfoToRemove); - - final List services = new ArrayList<>(); - services.addAll(mShadowInputMethodManager.getInputMethodList()); - services.remove(serviceToRemove); - mShadowInputMethodManager.setInputMethodList(services); - - final Intent intent = DynamicIndexableContentMonitor.getIMEServiceIntent(packageName); - mRobolectricPackageManager.removeResolveInfosForIntent(intent, packageName); - mRobolectricPackageManager.removePackage(packageName); - - extractPackageMonitor() - .onPackageDisappeared(packageName, PackageMonitor.PACKAGE_PERMANENT_CHANGE); - Robolectric.flushBackgroundThreadScheduler(); - } - - private AccessibilityServiceInfo buildAccessibilityServiceInfo(String packageName) - throws IOException, XmlPullParserException { - return new AccessibilityServiceInfo( - buildResolveInfo(packageName, "A11yService"), mActivity); - } - - private static InputMethodInfo buildInputMethodInfo(ResolveInfo resolveInfo) { - return new InputMethodInfo(resolveInfo, false /* isAuxIme */, "SettingsActivity", - null /* subtypes */, 0 /* defaultResId */, false /* forceDefault */); - } - - private static ResolveInfo buildResolveInfo(String packageName, String className) { - final ResolveInfo resolveInfo = new ResolveInfo(); - resolveInfo.serviceInfo = new ServiceInfo(); - resolveInfo.serviceInfo.packageName = packageName; - resolveInfo.serviceInfo.name = className; - // To workaround that RobolectricPackageManager.removeResolveInfosForIntent() only works - // for activity/broadcast resolver. - resolveInfo.activityInfo = new ActivityInfo(); - resolveInfo.activityInfo.packageName = packageName; - resolveInfo.activityInfo.name = className; - - return resolveInfo; - } - - private static boolean isUnderTest(Object object) { - return object.getClass().getName().startsWith( - DynamicIndexableContentMonitor.class.getName()); - } -} diff --git a/tests/robotests/src/com/android/settings/search/InputDeviceResultLoaderTest.java b/tests/robotests/src/com/android/settings/search/InputDeviceResultLoaderTest.java new file mode 100644 index 00000000000..a955af179ff --- /dev/null +++ b/tests/robotests/src/com/android/settings/search/InputDeviceResultLoaderTest.java @@ -0,0 +1,173 @@ +/* + * 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 android.content.Context.INPUT_METHOD_SERVICE; +import static com.android.settings.search.InputDeviceResultLoader.PHYSICAL_KEYBOARD_FRAGMENT; +import static com.android.settings.search.InputDeviceResultLoader.VIRTUAL_KEYBOARD_FRAGMENT; +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.pm.ServiceInfo; +import android.hardware.input.InputManager; +import android.view.InputDevice; +import android.view.inputmethod.InputMethodInfo; +import android.view.inputmethod.InputMethodManager; + +import com.android.settings.R; +import com.android.settings.TestConfig; +import com.android.settings.dashboard.SiteMapManager; +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.testutils.shadow.ShadowInputDevice; + +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.ArrayList; +import java.util.List; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, + sdk = TestConfig.SDK_VERSION, + shadows = { + ShadowInputDevice.class + }) +public class InputDeviceResultLoaderTest { + + private static final String QUERY = "test_query"; + private static final List PHYSICAL_KEYBOARD_BREADCRUMB; + private static final List VIRTUAL_KEYBOARD_BREADCRUMB; + + static { + PHYSICAL_KEYBOARD_BREADCRUMB = new ArrayList<>(); + VIRTUAL_KEYBOARD_BREADCRUMB = new ArrayList<>(); + PHYSICAL_KEYBOARD_BREADCRUMB.add("Settings"); + PHYSICAL_KEYBOARD_BREADCRUMB.add("physical keyboard"); + VIRTUAL_KEYBOARD_BREADCRUMB.add("Settings"); + VIRTUAL_KEYBOARD_BREADCRUMB.add("virtual keyboard"); + } + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private Context mContext; + @Mock + private SiteMapManager mSiteMapManager; + @Mock + private InputManager mInputManager; + @Mock + private InputMethodManager mImm; + @Mock + private PackageManager mPackageManager; + + private InputDeviceResultLoader mLoader; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + when(mContext.getApplicationContext()).thenReturn(mContext); + when(mContext.getSystemService(Context.INPUT_SERVICE)) + .thenReturn(mInputManager); + when(mContext.getSystemService(INPUT_METHOD_SERVICE)) + .thenReturn(mImm); + when(mContext.getPackageManager()) + .thenReturn(mPackageManager); + when(mContext.getString(anyInt())) + .thenAnswer(invocation -> RuntimeEnvironment.application.getString( + (Integer) invocation.getArguments()[0])); + mLoader = new InputDeviceResultLoader(mContext, QUERY, mSiteMapManager); + } + + @After + public void tearDown() { + ShadowInputDevice.reset(); + } + + @Test + public void query_noKeyboard_shouldNotReturnAnything() { + assertThat(mLoader.loadInBackground()).isEmpty(); + } + + @Test + public void query_hasPhysicalKeyboard_match() { + addPhysicalKeyboard(QUERY); + when(mSiteMapManager.buildBreadCrumb(mContext, PHYSICAL_KEYBOARD_FRAGMENT, + RuntimeEnvironment.application.getString(R.string.physical_keyboard_title))) + .thenReturn(PHYSICAL_KEYBOARD_BREADCRUMB); + + final List results = new ArrayList<>(mLoader.loadInBackground()); + + assertThat(results).hasSize(1); + assertThat(results.get(0).title).isEqualTo(QUERY); + assertThat(results.get(0).breadcrumbs) + .containsExactlyElementsIn(PHYSICAL_KEYBOARD_BREADCRUMB); + } + + @Test + public void query_hasVirtualKeyboard_match() { + addVirtualKeyboard(QUERY); + when(mSiteMapManager.buildBreadCrumb(mContext, VIRTUAL_KEYBOARD_FRAGMENT, + RuntimeEnvironment.application.getString(R.string.add_virtual_keyboard))) + .thenReturn(VIRTUAL_KEYBOARD_BREADCRUMB); + + final List results = new ArrayList<>(mLoader.loadInBackground()); + assertThat(results).hasSize(1); + assertThat(results.get(0).title).isEqualTo(QUERY); + assertThat(results.get(0).breadcrumbs) + .containsExactlyElementsIn(VIRTUAL_KEYBOARD_BREADCRUMB); + } + + @Test + public void query_hasPhysicalVirtualKeyboard_doNotMatch() { + addPhysicalKeyboard("abc"); + addVirtualKeyboard("def"); + + assertThat(mLoader.loadInBackground()).isEmpty(); + verifyZeroInteractions(mSiteMapManager); + } + + private void addPhysicalKeyboard(String name) { + final InputDevice device = mock(InputDevice.class); + when(device.isVirtual()).thenReturn(false); + when(device.isFullKeyboard()).thenReturn(true); + when(device.getName()).thenReturn(name); + ShadowInputDevice.sDeviceIds = new int[]{0}; + ShadowInputDevice.addDevice(0, device); + } + + private void addVirtualKeyboard(String name) { + final List imis = new ArrayList<>(); + final InputMethodInfo info = mock(InputMethodInfo.class); + imis.add(info); + when(info.getServiceInfo()).thenReturn(new ServiceInfo()); + when(info.loadLabel(mPackageManager)).thenReturn(name); + info.getServiceInfo().packageName = "pkg"; + info.getServiceInfo().name = "class"; + when(mImm.getInputMethodList()).thenReturn(imis); + } + +} diff --git a/tests/robotests/src/com/android/settings/search/MockAccessibilityLoader.java b/tests/robotests/src/com/android/settings/search/MockAccessibilityLoader.java new file mode 100644 index 00000000000..0a06a351915 --- /dev/null +++ b/tests/robotests/src/com/android/settings/search/MockAccessibilityLoader.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 MockAccessibilityLoader extends AccessibilityServiceResultLoader { + + public MockAccessibilityLoader(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/MockAccessiblityLoader.java b/tests/robotests/src/com/android/settings/search/MockInputDeviceResultLoader.java similarity index 88% rename from tests/robotests/src/com/android/settings/search/MockAccessiblityLoader.java rename to tests/robotests/src/com/android/settings/search/MockInputDeviceResultLoader.java index aa9b778e299..2c16b14a3b0 100644 --- a/tests/robotests/src/com/android/settings/search/MockAccessiblityLoader.java +++ b/tests/robotests/src/com/android/settings/search/MockInputDeviceResultLoader.java @@ -21,9 +21,8 @@ import android.content.Context; import java.util.HashSet; import java.util.Set; -public class MockAccessiblityLoader extends AccessibilityServiceResultLoader { - - public MockAccessiblityLoader(Context context) { +public class MockInputDeviceResultLoader extends InputDeviceResultLoader { + public MockInputDeviceResultLoader(Context context) { super(context, "test_query", null); } diff --git a/tests/robotests/src/com/android/settings/search/SearchFragmentTest.java b/tests/robotests/src/com/android/settings/search/SearchFragmentTest.java index 658880528ab..71c31aa149b 100644 --- a/tests/robotests/src/com/android/settings/search/SearchFragmentTest.java +++ b/tests/robotests/src/com/android/settings/search/SearchFragmentTest.java @@ -17,6 +17,20 @@ package com.android.settings.search; +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.argThat; +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.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import android.app.LoaderManager; import android.content.Context; import android.content.Intent; @@ -28,10 +42,10 @@ import android.view.View; import com.android.internal.logging.nano.MetricsProto; import com.android.settings.R; import com.android.settings.SettingsActivity; -import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; import com.android.settings.testutils.DatabaseTestUtils; import com.android.settings.testutils.FakeFeatureFactory; +import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.SettingsShadowResources; import org.junit.After; @@ -52,20 +66,6 @@ import org.robolectric.util.ReflectionHelpers; import java.util.Set; -import static com.google.common.truth.Truth.assertThat; -import static org.mockito.ArgumentMatchers.nullable; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.argThat; -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.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - @RunWith(SettingsRobolectricTestRunner.class) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION, @@ -83,6 +83,8 @@ public class SearchFragmentTest { private InstalledAppResultLoader mInstalledAppResultLoader; @Mock private AccessibilityServiceResultLoader mAccessibilityServiceResultLoader; + @Mock + private InputDeviceResultLoader mInputDeviceResultLoader; @Mock private SavedQueryLoader mSavedQueryLoader; @@ -118,6 +120,9 @@ public class SearchFragmentTest { when(mFeatureFactory.searchFeatureProvider .getAccessibilityServiceResultLoader(any(Context.class), anyString())) .thenReturn(mAccessibilityServiceResultLoader); + when(mFeatureFactory.searchFeatureProvider + .getInputDeviceResultLoader(any(Context.class), anyString())) + .thenReturn(mInputDeviceResultLoader); when(mFeatureFactory.searchFeatureProvider.getSavedQueryLoader(any(Context.class))) .thenReturn(mSavedQueryLoader); @@ -178,6 +183,9 @@ public class SearchFragmentTest { when(mFeatureFactory.searchFeatureProvider .getAccessibilityServiceResultLoader(any(Context.class), anyString())) .thenReturn(mAccessibilityServiceResultLoader); + when(mFeatureFactory.searchFeatureProvider + .getInputDeviceResultLoader(any(Context.class), anyString())) + .thenReturn(mInputDeviceResultLoader); when(mFeatureFactory.searchFeatureProvider.getSavedQueryLoader(any(Context.class))) .thenReturn(mSavedQueryLoader); @@ -236,6 +244,9 @@ public class SearchFragmentTest { when(mFeatureFactory.searchFeatureProvider .getAccessibilityServiceResultLoader(any(Context.class), anyString())) .thenReturn(mAccessibilityServiceResultLoader); + when(mFeatureFactory.searchFeatureProvider + .getInputDeviceResultLoader(any(Context.class), anyString())) + .thenReturn(mInputDeviceResultLoader); when(mFeatureFactory.searchFeatureProvider.getSavedQueryLoader(any(Context.class))) .thenReturn(mSavedQueryLoader); ActivityController activityController = @@ -270,6 +281,9 @@ public class SearchFragmentTest { when(mFeatureFactory.searchFeatureProvider .getAccessibilityServiceResultLoader(any(Context.class), anyString())) .thenReturn(mAccessibilityServiceResultLoader); + when(mFeatureFactory.searchFeatureProvider + .getInputDeviceResultLoader(any(Context.class), anyString())) + .thenReturn(mInputDeviceResultLoader); when(mFeatureFactory.searchFeatureProvider.getSavedQueryLoader(any(Context.class))) .thenReturn(mSavedQueryLoader); @@ -349,7 +363,10 @@ public class SearchFragmentTest { .thenReturn(new MockAppLoader(RuntimeEnvironment.application)); when(mFeatureFactory.searchFeatureProvider .getAccessibilityServiceResultLoader(any(Context.class), anyString())) - .thenReturn(new MockAccessiblityLoader(RuntimeEnvironment.application)); + .thenReturn(new MockAccessibilityLoader(RuntimeEnvironment.application)); + when(mFeatureFactory.searchFeatureProvider + .getInputDeviceResultLoader(any(Context.class), anyString())) + .thenReturn(new MockInputDeviceResultLoader(RuntimeEnvironment.application)); when(mFeatureFactory.searchFeatureProvider.getSavedQueryLoader(any(Context.class))) .thenReturn(mSavedQueryLoader); ActivityController activityController = diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDynamicIndexableContentMonitor.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDynamicIndexableContentMonitor.java deleted file mode 100644 index de5d243624f..00000000000 --- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDynamicIndexableContentMonitor.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.android.settings.testutils.shadow; - -import android.app.Activity; -import android.os.UserManager; -import com.android.settings.search.DynamicIndexableContentMonitor; -import org.robolectric.annotation.Implementation; -import org.robolectric.annotation.Implements; -import org.robolectric.annotation.RealObject; - -/** - * A shadow class of {@link DynamicIndexableContentMonitor}. The real implementation of - * {@link DynamicIndexableContentMonitor#register} calls {@link UserManager#isUserUnlocked()}, which - * Robolectric has not yet been updated to support, so throws a NoSuchMethodError exception. - */ -// TODO: Delete this once Robolectric is updated to the latest SDK. -@Implements(DynamicIndexableContentMonitor.class) -public class ShadowDynamicIndexableContentMonitor { - - @Implementation - public void register(Activity activity, int loaderId) { - } -}