diff options
author | Xiyuan Xia <xiyuan@google.com> | 2015-06-02 14:55:32 -0700 |
---|---|---|
committer | Xiyuan Xia <xiyuan@google.com> | 2015-06-10 08:43:28 -0700 |
commit | 86a554091d0705f2152fcf1d78ca1c7720d9842c (patch) | |
tree | e168fef6ad80da3a545c80101935d68198e438f1 /src/com/android/settings | |
parent | 275e6f75208c08eb925048a330ed4aab96e51033 (diff) | |
download | packages_apps_Settings-86a554091d0705f2152fcf1d78ca1c7720d9842c.zip packages_apps_Settings-86a554091d0705f2152fcf1d78ca1c7720d9842c.tar.gz packages_apps_Settings-86a554091d0705f2152fcf1d78ca1c7720d9842c.tar.bz2 |
Implement default assist app setting
- Add "None" support to AppListPreference
- Add DefaultAssistPreference to manage assist;
- Add AppListPreferenceWithSettings to show a settings icon;
- Implement DefaultAssistPreference based on AppListPreferenceWithSettings;
- Move voice input settings into ManageAssist and implement it
based on AppListPreferenceWithSettings;
Bug:20210110
Change-Id: If283b8b55a46b428ecfa6e45dc2123292b1d4302
Diffstat (limited to 'src/com/android/settings')
13 files changed, 554 insertions, 548 deletions
diff --git a/src/com/android/settings/AppListPreference.java b/src/com/android/settings/AppListPreference.java index 3cc91cd..d5e0c3b 100644 --- a/src/com/android/settings/AppListPreference.java +++ b/src/com/android/settings/AppListPreference.java @@ -35,13 +35,20 @@ import android.widget.ImageView; import android.widget.ListAdapter; import android.widget.TextView; +import java.util.ArrayList; +import java.util.List; + /** * Extends ListPreference to allow us to show the icons for a given list of applications. We do this * because the names of applications are very similar and the user may not be able to determine what * app they are selecting without an icon. */ public class AppListPreference extends ListPreference { + + public static final String ITEM_NONE_VALUE = ""; + private Drawable[] mEntryDrawables; + private boolean mShowItemNone = false; public class AppArrayAdapter extends ArrayAdapter<CharSequence> { private Drawable[] mImageDrawables = null; @@ -78,38 +85,45 @@ public class AppListPreference extends ListPreference { super(context, attrs); } + public void setShowItemNone(boolean showItemNone) { + mShowItemNone = showItemNone; + } + public void setPackageNames(CharSequence[] packageNames, CharSequence defaultPackageName) { // Look up all package names in PackageManager. Skip ones we can't find. - int foundPackages = 0; PackageManager pm = getContext().getPackageManager(); - ApplicationInfo[] appInfos = new ApplicationInfo[packageNames.length]; + final int entryCount = packageNames.length + (mShowItemNone ? 1 : 0); + List<CharSequence> applicationNames = new ArrayList<>(entryCount); + List<CharSequence> validatedPackageNames = new ArrayList<>(entryCount); + List<Drawable> entryDrawables = new ArrayList<>(entryCount); + int selectedIndex = -1; for (int i = 0; i < packageNames.length; i++) { try { - appInfos[i] = pm.getApplicationInfo(packageNames[i].toString(), 0); - foundPackages++; - } catch (NameNotFoundException e) { - // Leave appInfos[i] uninitialized; it will be skipped in the list. - } - } - - // Show the label and icon for each application package. - CharSequence[] applicationNames = new CharSequence[foundPackages]; - mEntryDrawables = new Drawable[foundPackages]; - int index = 0; - int selectedIndex = -1; - for (ApplicationInfo appInfo : appInfos) { - if (appInfo != null) { - applicationNames[index] = appInfo.loadLabel(pm); - mEntryDrawables[index] = appInfo.loadIcon(pm); + ApplicationInfo appInfo = pm.getApplicationInfo(packageNames[i].toString(), 0); + applicationNames.add(appInfo.loadLabel(pm)); + validatedPackageNames.add(appInfo.packageName); + entryDrawables.add(appInfo.loadIcon(pm)); if (defaultPackageName != null && appInfo.packageName.contentEquals(defaultPackageName)) { - selectedIndex = index; + selectedIndex = i; } - index++; + } catch (NameNotFoundException e) { + // Skip unknown packages. } } - setEntries(applicationNames); - setEntryValues(packageNames); + + if (mShowItemNone) { + applicationNames.add( + getContext().getResources().getText(R.string.app_list_preference_none)); + validatedPackageNames.add(ITEM_NONE_VALUE); + entryDrawables.add(getContext().getDrawable(R.drawable.ic_remove_circle)); + } + + setEntries(applicationNames.toArray(new CharSequence[applicationNames.size()])); + setEntryValues( + validatedPackageNames.toArray(new CharSequence[validatedPackageNames.size()])); + mEntryDrawables = entryDrawables.toArray(new Drawable[entryDrawables.size()]); + if (selectedIndex != -1) { setValueIndex(selectedIndex); } else { @@ -117,25 +131,32 @@ public class AppListPreference extends ListPreference { } } + protected ListAdapter createListAdapter() { + final String selectedValue = getValue(); + final boolean selectedNone = selectedValue == null || + (mShowItemNone && selectedValue.contentEquals(ITEM_NONE_VALUE)); + int selectedIndex = selectedNone ? -1 : findIndexOfValue(selectedValue); + return new AppArrayAdapter(getContext(), + R.layout.app_preference_item, getEntries(), mEntryDrawables, selectedIndex); + } + @Override protected void onPrepareDialogBuilder(Builder builder) { - int selectedIndex = findIndexOfValue(getValue()); - ListAdapter adapter = new AppArrayAdapter(getContext(), - R.layout.app_preference_item, getEntries(), mEntryDrawables, selectedIndex); - builder.setAdapter(adapter, this); + builder.setAdapter(createListAdapter(), this); super.onPrepareDialogBuilder(builder); } @Override protected Parcelable onSaveInstanceState() { Parcelable superState = super.onSaveInstanceState(); - return new SavedState(getEntryValues(), getValue(), superState); + return new SavedState(getEntryValues(), getValue(), mShowItemNone, superState); } @Override protected void onRestoreInstanceState(Parcelable state) { if (state instanceof SavedState) { SavedState savedState = (SavedState) state; + mShowItemNone = savedState.showItemNone; setPackageNames(savedState.entryValues, savedState.value); super.onRestoreInstanceState(savedState.superState); } else { @@ -147,11 +168,14 @@ public class AppListPreference extends ListPreference { public final CharSequence[] entryValues; public final CharSequence value; + public final boolean showItemNone; public final Parcelable superState; - public SavedState(CharSequence[] entryValues, CharSequence value, Parcelable superState) { + public SavedState(CharSequence[] entryValues, CharSequence value, boolean showItemNone, + Parcelable superState) { this.entryValues = entryValues; this.value = value; + this.showItemNone = showItemNone; this.superState = superState; } @@ -164,6 +188,7 @@ public class AppListPreference extends ListPreference { public void writeToParcel(Parcel dest, int flags) { dest.writeCharSequenceArray(entryValues); dest.writeCharSequence(value); + dest.writeInt(showItemNone ? 1 : 0); dest.writeParcelable(superState, flags); } @@ -172,8 +197,9 @@ public class AppListPreference extends ListPreference { public SavedState createFromParcel(Parcel source) { CharSequence[] entryValues = source.readCharSequenceArray(); CharSequence value = source.readCharSequence(); + boolean showItemNone = source.readInt() != 0; Parcelable superState = source.readParcelable(getClass().getClassLoader()); - return new SavedState(entryValues, value, superState); + return new SavedState(entryValues, value, showItemNone, superState); } @Override diff --git a/src/com/android/settings/AppListPreferenceWithSettings.java b/src/com/android/settings/AppListPreferenceWithSettings.java new file mode 100644 index 0000000..bbbd332 --- /dev/null +++ b/src/com/android/settings/AppListPreferenceWithSettings.java @@ -0,0 +1,59 @@ +package com.android.settings; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; + +/** + * An AppListPreference with optional settings button. + */ +public class AppListPreferenceWithSettings extends AppListPreference { + + private View mSettingsIcon; + private ComponentName mSettingsComponent; + + public AppListPreferenceWithSettings(Context context, AttributeSet attrs) { + super(context, attrs); + setWidgetLayoutResource(R.layout.preference_widget_settings); + } + + @Override + protected void onBindView(View view) { + super.onBindView(view); + + mSettingsIcon = view.findViewById(R.id.settings_button); + mSettingsIcon.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(Intent.ACTION_MAIN); + intent.setComponent(mSettingsComponent); + getContext().startActivity(new Intent(intent)); + } + }); + + ViewGroup container = (ViewGroup) mSettingsIcon.getParent(); + container.setPaddingRelative(0, 0, 0, 0); + + updateSettingsVisibility(); + } + + private void updateSettingsVisibility() { + if (mSettingsIcon == null) { + return; + } + + if (mSettingsComponent == null) { + mSettingsIcon.setVisibility(View.GONE); + } else { + mSettingsIcon.setVisibility(View.VISIBLE); + } + } + + protected void setSettingsComponent(ComponentName settings) { + mSettingsComponent = settings; + updateSettingsVisibility(); + } +} diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java index 5a6a2f0..5fb94f0 100644 --- a/src/com/android/settings/Settings.java +++ b/src/com/android/settings/Settings.java @@ -41,7 +41,6 @@ public class Settings extends SettingsActivity { public static class InputMethodAndLanguageSettingsActivity extends SettingsActivity { /* empty */ } public static class KeyboardLayoutPickerActivity extends SettingsActivity { /* empty */ } public static class InputMethodAndSubtypeEnablerActivity extends SettingsActivity { /* empty */ } - public static class VoiceInputSettingsActivity extends SettingsActivity { /* empty */ } public static class SpellCheckersSettingsActivity extends SettingsActivity { /* empty */ } public static class LocalePickerActivity extends SettingsActivity { /* empty */ } public static class UserDictionarySettingsActivity extends SettingsActivity { /* empty */ } @@ -50,6 +49,7 @@ public class Settings extends SettingsActivity { public static class DeviceInfoSettingsActivity extends SettingsActivity { /* empty */ } public static class ApplicationSettingsActivity extends SettingsActivity { /* empty */ } public static class ManageApplicationsActivity extends SettingsActivity { /* empty */ } + public static class ManageAssistActivity extends SettingsActivity { /* empty */ } public static class AllApplicationsActivity extends SettingsActivity { /* empty */ } public static class HighPowerApplicationsActivity extends SettingsActivity { /* empty */ } public static class AppOpsSummaryActivity extends SettingsActivity { diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java index 3cef9ce..89231df 100644 --- a/src/com/android/settings/SettingsActivity.java +++ b/src/com/android/settings/SettingsActivity.java @@ -72,6 +72,7 @@ import com.android.settings.accounts.AccountSettings; import com.android.settings.accounts.AccountSyncSettings; import com.android.settings.applications.InstalledAppDetails; import com.android.settings.applications.ManageApplications; +import com.android.settings.applications.ManageAssist; import com.android.settings.applications.ProcessStatsUi; import com.android.settings.applications.UsageAccessDetails; import com.android.settings.bluetooth.BluetoothSettings; @@ -112,7 +113,6 @@ import com.android.settings.search.Index; import com.android.settings.sim.SimSettings; import com.android.settings.tts.TextToSpeechSettings; import com.android.settings.users.UserSettings; -import com.android.settings.voice.VoiceInputSettings; import com.android.settings.vpn2.VpnSettings; import com.android.settings.wfd.WifiDisplaySettings; import com.android.settings.widget.SwitchBar; @@ -290,7 +290,6 @@ public class SettingsActivity extends Activity DateTimeSettings.class.getName(), LocalePicker.class.getName(), InputMethodAndLanguageSettings.class.getName(), - VoiceInputSettings.class.getName(), SpellCheckersSettings.class.getName(), UserDictionaryList.class.getName(), UserDictionarySettings.class.getName(), @@ -298,6 +297,7 @@ public class SettingsActivity extends Activity DisplaySettings.class.getName(), DeviceInfoSettings.class.getName(), ManageApplications.class.getName(), + ManageAssist.class.getName(), ProcessStatsUi.class.getName(), NotificationStation.class.getName(), LocationSettings.class.getName(), diff --git a/src/com/android/settings/VoiceInputOutputSettings.java b/src/com/android/settings/VoiceInputOutputSettings.java index e052f8e..a264d50 100644 --- a/src/com/android/settings/VoiceInputOutputSettings.java +++ b/src/com/android/settings/VoiceInputOutputSettings.java @@ -31,7 +31,6 @@ public class VoiceInputOutputSettings { private static final String TAG = "VoiceInputOutputSettings"; private static final String KEY_VOICE_CATEGORY = "voice_category"; - private static final String KEY_VOICE_INPUT_SETTINGS = "voice_input_settings"; private static final String KEY_TTS_SETTINGS = "tts_settings"; private PreferenceGroup mParent; @@ -47,19 +46,16 @@ public class VoiceInputOutputSettings { } public void onCreate() { - mParent = mFragment.getPreferenceScreen(); mVoiceCategory = (PreferenceCategory) mParent.findPreference(KEY_VOICE_CATEGORY); - mVoiceInputSettingsPref = mVoiceCategory.findPreference(KEY_VOICE_INPUT_SETTINGS); mTtsSettingsPref = mVoiceCategory.findPreference(KEY_TTS_SETTINGS); populateOrRemovePreferences(); } private void populateOrRemovePreferences() { - boolean hasVoiceInputPrefs = populateOrRemoveVoiceInputPrefs(); boolean hasTtsPrefs = populateOrRemoveTtsPrefs(); - if (!hasVoiceInputPrefs && !hasTtsPrefs) { + if (!hasTtsPrefs) { // There were no TTS settings and no recognizer settings, // so it should be safe to hide the preference category // entirely. @@ -67,16 +63,6 @@ public class VoiceInputOutputSettings { } } - private boolean populateOrRemoveVoiceInputPrefs() { - VoiceInputHelper helper = new VoiceInputHelper(mFragment.getActivity()); - if (!helper.hasItems()) { - mVoiceCategory.removePreference(mVoiceInputSettingsPref); - return false; - } - - return true; - } - private boolean populateOrRemoveTtsPrefs() { if (mTtsEngines.getEngines().isEmpty()) { mVoiceCategory.removePreference(mTtsSettingsPref); diff --git a/src/com/android/settings/applications/DefaultAssistPreference.java b/src/com/android/settings/applications/DefaultAssistPreference.java new file mode 100644 index 0000000..260d4b9 --- /dev/null +++ b/src/com/android/settings/applications/DefaultAssistPreference.java @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2015 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.applications; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.provider.Settings; +import android.service.voice.VoiceInteractionService; +import android.service.voice.VoiceInteractionServiceInfo; +import android.speech.RecognitionService; +import android.util.AttributeSet; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; + +import com.android.settings.AppListPreferenceWithSettings; +import com.android.settings.R; + +import java.util.ArrayList; +import java.util.List; + +public class DefaultAssistPreference extends AppListPreferenceWithSettings { + + private static final String TAG = DefaultAssistPreference.class.getSimpleName(); + + private final List<Info> mAvailableAssistants = new ArrayList<>(); + + public DefaultAssistPreference(Context context, AttributeSet attrs) { + super(context, attrs); + setShowItemNone(true); + setDialogTitle(R.string.choose_assist_title); + } + + @Override + protected boolean persistString(String value) { + final Info info = findAssistantByPackageName(value); + if (info == null) { + setAssistNone(); + return true; + } + + if (info.isVoiceInteractionService()) { + setAssistService(info); + } else { + setAssistActivity(info); + } + return true; + } + + private void setAssistNone() { + Settings.Secure.putString(getContext().getContentResolver(), + Settings.Secure.ASSISTANT, ITEM_NONE_VALUE); + Settings.Secure.putString(getContext().getContentResolver(), + Settings.Secure.VOICE_INTERACTION_SERVICE, ""); + Settings.Secure.putString(getContext().getContentResolver(), + Settings.Secure.VOICE_RECOGNITION_SERVICE, getDefaultRecognizer()); + + setSummary(getContext().getText(R.string.default_assist_none)); + setSettingsComponent(null); + } + + private void setAssistService(Info serviceInfo) { + final String serviceComponentName = serviceInfo.component.flattenToShortString(); + final String serviceRecognizerName = new ComponentName( + serviceInfo.component.getPackageName(), + serviceInfo.voiceInteractionServiceInfo.getRecognitionService()) + .flattenToShortString(); + + Settings.Secure.putString(getContext().getContentResolver(), + Settings.Secure.ASSISTANT, serviceComponentName); + Settings.Secure.putString(getContext().getContentResolver(), + Settings.Secure.VOICE_INTERACTION_SERVICE, serviceComponentName); + Settings.Secure.putString(getContext().getContentResolver(), + Settings.Secure.VOICE_RECOGNITION_SERVICE, serviceRecognizerName); + + setSummary(getEntry()); + final String settingsActivity = + serviceInfo.voiceInteractionServiceInfo.getSettingsActivity(); + setSettingsComponent(settingsActivity == null ? + null : + new ComponentName(serviceInfo.component.getPackageName(), settingsActivity)); + } + + private void setAssistActivity(Info activityInfo) { + Settings.Secure.putString(getContext().getContentResolver(), + Settings.Secure.ASSISTANT, activityInfo.component.flattenToShortString()); + Settings.Secure.putString(getContext().getContentResolver(), + Settings.Secure.VOICE_INTERACTION_SERVICE, ""); + Settings.Secure.putString(getContext().getContentResolver(), + Settings.Secure.VOICE_RECOGNITION_SERVICE, getDefaultRecognizer()); + + setSummary(getEntry()); + setSettingsComponent(null); + } + + private String getDefaultRecognizer() { + ResolveInfo resolveInfo = getContext().getPackageManager().resolveService( + new Intent(RecognitionService.SERVICE_INTERFACE), + PackageManager.GET_META_DATA); + if (resolveInfo == null || resolveInfo.serviceInfo == null) { + Log.w(TAG, "Unable to resolve default voice recognition service."); + return ""; + } + + return new ComponentName(resolveInfo.serviceInfo.packageName, + resolveInfo.serviceInfo.name).flattenToShortString(); + } + + private Info findAssistantByPackageName(String packageName) { + for (int i = 0; i < mAvailableAssistants.size(); ++i) { + Info info = mAvailableAssistants.get(i); + if (info.component.getPackageName().equals(packageName)) { + return info; + } + } + return null; + } + + private void addAssistServices() { + PackageManager pm = getContext().getPackageManager(); + + List<ResolveInfo> services = pm.queryIntentServices( + new Intent(VoiceInteractionService.SERVICE_INTERFACE), + PackageManager.GET_META_DATA); + for (int i = 0; i < services.size(); ++i) { + ResolveInfo resolveInfo = services.get(i); + VoiceInteractionServiceInfo voiceInteractionServiceInfo = + new VoiceInteractionServiceInfo(pm, resolveInfo.serviceInfo); + if (!voiceInteractionServiceInfo.getSupportsAssist()) { + continue; + } + + mAvailableAssistants.add(new Info( + new ComponentName(resolveInfo.serviceInfo.packageName, + resolveInfo.serviceInfo.name), + voiceInteractionServiceInfo)); + } + } + + private void addAssistActivities() { + PackageManager pm = getContext().getPackageManager(); + + List<ResolveInfo> activities = pm.queryIntentActivities( + new Intent(Intent.ACTION_ASSIST), + PackageManager.MATCH_DEFAULT_ONLY); + for (int i = 0; i < activities.size(); ++i) { + ResolveInfo resolveInfo = activities.get(i); + mAvailableAssistants.add(new Info( + new ComponentName(resolveInfo.activityInfo.packageName, + resolveInfo.activityInfo.name))); + } + } + + public ComponentName getCurrentAssist() { + String currentSetting = Settings.Secure.getString(getContext().getContentResolver(), + Settings.Secure.ASSISTANT); + return currentSetting == null ? null : ComponentName.unflattenFromString(currentSetting); + } + + public void refreshAssistApps() { + mAvailableAssistants.clear(); + addAssistServices(); + addAssistActivities(); + + List<String> packages = new ArrayList<>(); + for (int i = 0; i < mAvailableAssistants.size(); ++i) { + String packageName = mAvailableAssistants.get(i).component.getPackageName(); + if (packages.contains(packageName)) { + // A service appears before an activity thus overrides it if from the same package. + continue; + } + packages.add(packageName); + } + + ComponentName currentAssist = getCurrentAssist(); + setPackageNames(packages.toArray(new String[packages.size()]), + currentAssist == null ? null : currentAssist.getPackageName()); + } + + private static class Info { + public final ComponentName component; + public final VoiceInteractionServiceInfo voiceInteractionServiceInfo; + + Info(ComponentName component) { + this.component = component; + this.voiceInteractionServiceInfo = null; + } + + Info(ComponentName component, VoiceInteractionServiceInfo voiceInteractionServiceInfo) { + this.component = component; + this.voiceInteractionServiceInfo = voiceInteractionServiceInfo; + } + + public boolean isVoiceInteractionService() { + return voiceInteractionServiceInfo != null; + } + } +} diff --git a/src/com/android/settings/applications/ManageAssist.java b/src/com/android/settings/applications/ManageAssist.java index d3bc0c8..f937811 100644 --- a/src/com/android/settings/applications/ManageAssist.java +++ b/src/com/android/settings/applications/ManageAssist.java @@ -16,6 +16,9 @@ package com.android.settings.applications; +import android.app.AlertDialog; +import android.content.ComponentName; +import android.content.DialogInterface; import android.os.Bundle; import android.preference.Preference; import android.preference.SwitchPreference; @@ -25,6 +28,7 @@ import com.android.internal.logging.MetricsLogger; import com.android.settings.InstrumentedFragment; import com.android.settings.R; import com.android.settings.SettingsPreferenceFragment; +import com.android.settings.voice.VoiceInputListPreference; /** * Settings screen to manage everything about assist. @@ -32,18 +36,29 @@ import com.android.settings.SettingsPreferenceFragment; public class ManageAssist extends SettingsPreferenceFragment implements Preference.OnPreferenceChangeListener { + private static final String KEY_DEFAULT_ASSIST = "default_assist"; private static final String KEY_CONTEXT = "context"; + private static final String KEY_VOICE_INPUT = "voice_input_settings"; + private DefaultAssistPreference mDefaultAssitPref; private SwitchPreference mContextPref; + private VoiceInputListPreference mVoiceInputPref; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); addPreferencesFromResource(R.xml.manage_assist); + + mDefaultAssitPref = (DefaultAssistPreference) findPreference(KEY_DEFAULT_ASSIST); + mDefaultAssitPref.setOnPreferenceChangeListener(this); + mContextPref = (SwitchPreference) findPreference(KEY_CONTEXT); mContextPref.setChecked(Settings.Secure.getInt(getContentResolver(), Settings.Secure.ASSIST_STRUCTURE_ENABLED, 1) != 0); mContextPref.setOnPreferenceChangeListener(this); + + mVoiceInputPref = (VoiceInputListPreference) findPreference(KEY_VOICE_INPUT); + updateUi(); } @Override @@ -58,6 +73,64 @@ public class ManageAssist extends SettingsPreferenceFragment (boolean) newValue ? 1 : 0); return true; } + if (preference == mDefaultAssitPref) { + String newAssitPackage = (String)newValue; + if (newAssitPackage == null || + newAssitPackage.contentEquals(DefaultAssistPreference.ITEM_NONE_VALUE)) { + setDefaultAssist(DefaultAssistPreference.ITEM_NONE_VALUE); + return false; + } + + final String currentPackage = mDefaultAssitPref.getValue(); + if (currentPackage == null || !newAssitPackage.contentEquals(currentPackage)) { + confirmNewAssist(newAssitPackage); + } + return false; + } return false; } + + private void updateUi() { + mDefaultAssitPref.refreshAssistApps(); + + final ComponentName currentAssist = mDefaultAssitPref.getCurrentAssist(); + final boolean hasAssistant = currentAssist != null; + if (hasAssistant) { + getPreferenceScreen().addPreference(mContextPref); + } else { + getPreferenceScreen().removePreference(mContextPref); + } + + mVoiceInputPref.setAssistRestrict(currentAssist); + mVoiceInputPref.refreshVoiceInputs(); + } + + private void confirmNewAssist(final String newAssitPackage) { + final int selected = mDefaultAssitPref.findIndexOfValue(newAssitPackage); + final CharSequence appLabel = mDefaultAssitPref.getEntries()[selected]; + + final String title = getString(R.string.assistant_security_warning_title, appLabel); + final String message = getString(R.string.assistant_security_warning, appLabel); + + final DialogInterface.OnClickListener onAgree = new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + setDefaultAssist(newAssitPackage); + } + }; + + AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); + builder.setTitle(title) + .setMessage(message) + .setCancelable(true) + .setPositiveButton(R.string.assistant_security_warning_agree, onAgree) + .setNegativeButton(R.string.assistant_security_warning_disagree, null); + AlertDialog dialog = builder.create(); + dialog.show(); + } + + private void setDefaultAssist(String assistPackage) { + mDefaultAssitPref.setValue(assistPackage); + updateUi(); + } } diff --git a/src/com/android/settings/inputmethod/InputMethodAndLanguageSettings.java b/src/com/android/settings/inputmethod/InputMethodAndLanguageSettings.java index 8f23ce9..93ece66 100644 --- a/src/com/android/settings/inputmethod/InputMethodAndLanguageSettings.java +++ b/src/com/android/settings/inputmethod/InputMethodAndLanguageSettings.java @@ -790,14 +790,6 @@ public class InputMethodAndLanguageSettings extends SettingsPreferenceFragment indexables.add(indexable); } - // Voice input - indexable = new SearchIndexableRaw(context); - indexable.key = "voice_input_settings"; - indexable.title = context.getString(R.string.voice_input_settings); - indexable.screenTitle = screenTitle; - indexable.keywords = context.getString(R.string.keywords_voice_input); - indexables.add(indexable); - // Text-to-speech. TtsEngines ttsEngines = new TtsEngines(context); if (!ttsEngines.getEngines().isEmpty()) { diff --git a/src/com/android/settings/search/Ranking.java b/src/com/android/settings/search/Ranking.java index 6481aba..3edfee7 100644 --- a/src/com/android/settings/search/Ranking.java +++ b/src/com/android/settings/search/Ranking.java @@ -49,7 +49,6 @@ import com.android.settings.notification.ZenModeSettings; import com.android.settings.print.PrintSettingsFragment; import com.android.settings.sim.SimSettings; import com.android.settings.users.UserSettings; -import com.android.settings.voice.VoiceInputSettings; import com.android.settings.wifi.AdvancedWifiSettings; import com.android.settings.wifi.SavedAccessPointsWifiSettings; import com.android.settings.wifi.WifiSettings; @@ -154,7 +153,6 @@ public final class Ranking { // IMEs sRankMap.put(InputMethodAndLanguageSettings.class.getName(), RANK_IME); - sRankMap.put(VoiceInputSettings.class.getName(), RANK_IME); // Privacy sRankMap.put(PrivacySettings.class.getName(), RANK_PRIVACY); diff --git a/src/com/android/settings/search/SearchIndexableResources.java b/src/com/android/settings/search/SearchIndexableResources.java index 7cb0dd1..f3c0b42 100644 --- a/src/com/android/settings/search/SearchIndexableResources.java +++ b/src/com/android/settings/search/SearchIndexableResources.java @@ -50,7 +50,6 @@ import com.android.settings.notification.ZenModeSettings; import com.android.settings.print.PrintSettingsFragment; import com.android.settings.sim.SimSettings; import com.android.settings.users.UserSettings; -import com.android.settings.voice.VoiceInputSettings; import com.android.settings.wifi.AdvancedWifiSettings; import com.android.settings.wifi.SavedAccessPointsWifiSettings; import com.android.settings.wifi.WifiSettings; @@ -248,13 +247,6 @@ public final class SearchIndexableResources { InputMethodAndLanguageSettings.class.getName(), R.drawable.ic_settings_language)); - sResMap.put(VoiceInputSettings.class.getName(), - new SearchIndexableResource( - Ranking.getRankForClassName(VoiceInputSettings.class.getName()), - NO_DATA_RES_ID, - VoiceInputSettings.class.getName(), - R.drawable.ic_settings_language)); - sResMap.put(PrivacySettings.class.getName(), new SearchIndexableResource( Ranking.getRankForClassName(PrivacySettings.class.getName()), diff --git a/src/com/android/settings/voice/VoiceInputListPreference.java b/src/com/android/settings/voice/VoiceInputListPreference.java new file mode 100644 index 0000000..a131d21 --- /dev/null +++ b/src/com/android/settings/voice/VoiceInputListPreference.java @@ -0,0 +1,148 @@ +package com.android.settings.voice; + +import android.content.ComponentName; +import android.content.Context; +import android.provider.Settings; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.ListAdapter; + +import com.android.settings.AppListPreferenceWithSettings; +import com.android.settings.R; + +import java.util.ArrayList; +import java.util.List; + +public class VoiceInputListPreference extends AppListPreferenceWithSettings { + + private VoiceInputHelper mHelper; + + // The assist component name to restrict available voice inputs. + private ComponentName mAssistRestrict; + + private final List<Integer> mAvailableIndexes = new ArrayList<>(); + + public VoiceInputListPreference(Context context, AttributeSet attrs) { + super(context, attrs); + setDialogTitle(R.string.choose_voice_input_title); + } + + @Override + protected ListAdapter createListAdapter() { + return new CustomAdapter(getContext(), getEntries()); + } + + @Override + protected boolean persistString(String value) { + for (int i = 0; i < mHelper.mAvailableInteractionInfos.size(); ++i) { + VoiceInputHelper.InteractionInfo info = mHelper.mAvailableInteractionInfos.get(i); + if (info.key.equals(value)) { + Settings.Secure.putString(getContext().getContentResolver(), + Settings.Secure.VOICE_INTERACTION_SERVICE, value); + Settings.Secure.putString(getContext().getContentResolver(), + Settings.Secure.VOICE_RECOGNITION_SERVICE, + new ComponentName(info.service.packageName, + info.serviceInfo.getRecognitionService()) + .flattenToShortString()); + setSummary(getEntry()); + setSettingsComponent(info.settings); + return true; + } + } + + for (int i = 0; i < mHelper.mAvailableRecognizerInfos.size(); ++i) { + VoiceInputHelper.RecognizerInfo info = mHelper.mAvailableRecognizerInfos.get(i); + if (info.key.equals(value)) { + Settings.Secure.putString(getContext().getContentResolver(), + Settings.Secure.VOICE_INTERACTION_SERVICE, ""); + Settings.Secure.putString(getContext().getContentResolver(), + Settings.Secure.VOICE_RECOGNITION_SERVICE, value); + setSummary(getEntry()); + setSettingsComponent(info.settings); + return true; + } + } + + setSettingsComponent(null); + return true; + } + + @Override + public void setPackageNames(CharSequence[] packageNames, CharSequence defaultPackageName) { + // Skip since all entries are created from |mHelper|. + } + + public void setAssistRestrict(ComponentName assistRestrict) { + mAssistRestrict = assistRestrict; + } + + public void refreshVoiceInputs() { + mHelper = new VoiceInputHelper(getContext()); + mHelper.buildUi(); + + final String assistKey = + mAssistRestrict == null ? "" : mAssistRestrict.flattenToShortString(); + + mAvailableIndexes.clear(); + List<CharSequence> entries = new ArrayList<>(); + List<CharSequence> values = new ArrayList<>(); + for (int i = 0; i < mHelper.mAvailableInteractionInfos.size(); ++i) { + VoiceInputHelper.InteractionInfo info = mHelper.mAvailableInteractionInfos.get(i); + entries.add(info.appLabel); + values.add(info.key); + + if (info.key.contentEquals(assistKey)) { + mAvailableIndexes.add(i); + } + } + + final boolean assitIsService = !mAvailableIndexes.isEmpty(); + final int serviceCount = entries.size(); + + for (int i = 0; i < mHelper.mAvailableRecognizerInfos.size(); ++i) { + VoiceInputHelper.RecognizerInfo info = mHelper.mAvailableRecognizerInfos.get(i); + entries.add(info.label); + values.add(info.key); + if (!assitIsService) { + mAvailableIndexes.add(serviceCount + i); + } + } + setEntries(entries.toArray(new CharSequence[entries.size()])); + setEntryValues(values.toArray(new CharSequence[values.size()])); + + if (mHelper.mCurrentVoiceInteraction != null) { + setValue(mHelper.mCurrentVoiceInteraction.flattenToShortString()); + } else if (mHelper.mCurrentRecognizer != null) { + setValue(mHelper.mCurrentRecognizer.flattenToShortString()); + } else { + setValue(null); + } + } + + private class CustomAdapter extends ArrayAdapter<CharSequence> { + + public CustomAdapter(Context context, CharSequence[] objects) { + super(context, com.android.internal.R.layout.select_dialog_singlechoice_material, + android.R.id.text1, objects); + } + + @Override + public boolean areAllItemsEnabled() { + return false; + } + + @Override + public boolean isEnabled(int position) { + return mAvailableIndexes.contains(position); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View view = super.getView(position, convertView, parent); + view.setEnabled(isEnabled(position)); + return view; + } + } +} diff --git a/src/com/android/settings/voice/VoiceInputPreference.java b/src/com/android/settings/voice/VoiceInputPreference.java deleted file mode 100644 index 38ef0ca..0000000 --- a/src/com/android/settings/voice/VoiceInputPreference.java +++ /dev/null @@ -1,236 +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.voice; - -import android.app.AlertDialog; -import android.content.ComponentName; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.preference.Preference; -import android.util.Log; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Checkable; -import android.widget.CompoundButton; -import android.widget.RadioButton; - - -import com.android.settings.R; -import com.android.settings.Utils; - -public final class VoiceInputPreference extends Preference { - - private static final String TAG = "VoiceInputPreference"; - - private final CharSequence mLabel; - - private final CharSequence mAppLabel; - - private final CharSequence mAlertText; - - private final ComponentName mSettingsComponent; - - /** - * The shared radio button state, which button is checked etc. - */ - private final RadioButtonGroupState mSharedState; - - /** - * When true, the change callbacks on the radio button will not - * fire. - */ - private volatile boolean mPreventRadioButtonCallbacks; - - private View mSettingsIcon; - private RadioButton mRadioButton; - - private final CompoundButton.OnCheckedChangeListener mRadioChangeListener = - new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - onRadioButtonClicked(buttonView, isChecked); - } - }; - - public VoiceInputPreference(Context context, VoiceInputHelper.BaseInfo info, - CharSequence summary, CharSequence alertText, RadioButtonGroupState state) { - super(context); - setLayoutResource(R.layout.preference_tts_engine); - - mSharedState = state; - mLabel = info.label; - mAppLabel = info.appLabel; - mAlertText = alertText; - mSettingsComponent = info.settings; - mPreventRadioButtonCallbacks = false; - - setKey(info.key); - setTitle(info.label); - setSummary(summary); - } - - @Override - public View getView(View convertView, ViewGroup parent) { - if (mSharedState == null) { - throw new IllegalStateException("Call to getView() before a call to" + - "setSharedState()"); - } - - View view = super.getView(convertView, parent); - final RadioButton rb = (RadioButton) view.findViewById(R.id.tts_engine_radiobutton); - rb.setOnCheckedChangeListener(mRadioChangeListener); - - boolean isChecked = getKey().equals(mSharedState.getCurrentKey()); - if (isChecked) { - mSharedState.setCurrentChecked(rb); - } - - mPreventRadioButtonCallbacks = true; - rb.setChecked(isChecked); - mPreventRadioButtonCallbacks = false; - - mRadioButton = rb; - - View textLayout = view.findViewById(R.id.tts_engine_pref_text); - textLayout.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (!rb.isChecked()) { - onRadioButtonClicked(rb, true); - } - } - }); - - mSettingsIcon = view.findViewById(R.id.tts_engine_settings); - mSettingsIcon.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Intent intent = new Intent(Intent.ACTION_MAIN); - intent.setComponent(mSettingsComponent); - getContext().startActivity(new Intent(intent)); - } - }); - updateCheckedState(isChecked); - - return view; - } - - private boolean shouldDisplayAlert() { - return mAlertText != null; - } - - private void displayAlert( - final DialogInterface.OnClickListener positiveOnClickListener, - final DialogInterface.OnClickListener negativeOnClickListener) { - Log.i(TAG, "Displaying data alert for :" + getKey()); - - AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); - String msg = String.format(getContext().getResources().getConfiguration().locale, - mAlertText.toString(), mAppLabel); - builder.setTitle(android.R.string.dialog_alert_title) - .setMessage(msg) - .setCancelable(true) - .setPositiveButton(android.R.string.ok, positiveOnClickListener) - .setNegativeButton(android.R.string.cancel, negativeOnClickListener) - .setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override public void onCancel(DialogInterface dialog) { - negativeOnClickListener.onClick(dialog, DialogInterface.BUTTON_NEGATIVE); - } - }); - - AlertDialog dialog = builder.create(); - dialog.show(); - } - - public void doClick() { - mRadioButton.performClick(); - } - - void updateCheckedState(boolean isChecked) { - if (mSettingsComponent != null) { - mSettingsIcon.setVisibility(View.VISIBLE); - if (isChecked) { - mSettingsIcon.setEnabled(true); - mSettingsIcon.setAlpha(1); - } else { - mSettingsIcon.setEnabled(false); - mSettingsIcon.setAlpha(Utils.DISABLED_ALPHA); - } - } else { - mSettingsIcon.setVisibility(View.GONE); - } - } - - void onRadioButtonClicked(final CompoundButton buttonView, boolean isChecked) { - if (mPreventRadioButtonCallbacks) { - return; - } - if (mSharedState.getCurrentChecked() == buttonView) { - updateCheckedState(isChecked); - return; - } - - if (isChecked) { - // Should we alert user? if that's true, delay making engine current one. - if (shouldDisplayAlert()) { - displayAlert(new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - makeCurrentChecked(buttonView); - } - }, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - // Undo the click. - buttonView.setChecked(false); - } - } - ); - } else { - // Privileged engine, set it current - makeCurrentChecked(buttonView); - } - } else { - updateCheckedState(isChecked); - } - } - - void makeCurrentChecked(Checkable current) { - if (mSharedState.getCurrentChecked() != null) { - mSharedState.getCurrentChecked().setChecked(false); - } - mSharedState.setCurrentChecked(current); - mSharedState.setCurrentKey(getKey()); - updateCheckedState(true); - callChangeListener(mSharedState.getCurrentKey()); - current.setChecked(true); - } - - /** - * Holds all state that is common to this group of radio buttons, such - * as the currently selected key and the currently checked compound button. - * (which corresponds to this key). - */ - public interface RadioButtonGroupState { - String getCurrentKey(); - Checkable getCurrentChecked(); - - void setCurrentKey(String key); - void setCurrentChecked(Checkable current); - } -} diff --git a/src/com/android/settings/voice/VoiceInputSettings.java b/src/com/android/settings/voice/VoiceInputSettings.java deleted file mode 100644 index bac297e..0000000 --- a/src/com/android/settings/voice/VoiceInputSettings.java +++ /dev/null @@ -1,247 +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.voice; - -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.content.pm.ServiceInfo; -import android.preference.Preference; -import android.provider.Settings; -import android.service.voice.VoiceInteractionService; -import android.service.voice.VoiceInteractionServiceInfo; -import android.speech.RecognitionService; -import com.android.internal.logging.MetricsLogger; -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.settings.voice.VoiceInputPreference.RadioButtonGroupState; - -import android.os.Bundle; -import android.preference.PreferenceCategory; -import android.widget.Checkable; - -import java.util.ArrayList; -import java.util.List; - -public class VoiceInputSettings extends SettingsPreferenceFragment implements - Preference.OnPreferenceClickListener, RadioButtonGroupState, Indexable { - - private static final String TAG = "VoiceInputSettings"; - private static final boolean DBG = false; - - /** - * Preference key for the engine selection preference. - */ - private static final String KEY_SERVICE_PREFERENCE_SECTION = - "voice_service_preference_section"; - - private PreferenceCategory mServicePreferenceCategory; - - private CharSequence mInteractorSummary; - private CharSequence mRecognizerSummary; - private CharSequence mInteractorWarning; - - /** - * The currently selected engine. - */ - private String mCurrentKey; - - /** - * The engine checkbox that is currently checked. Saves us a bit of effort - * in deducing the right one from the currently selected engine. - */ - private Checkable mCurrentChecked; - - private VoiceInputHelper mHelper; - - @Override - protected int getMetricsCategory() { - return MetricsLogger.VOICE_INPUT; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.voice_input_settings); - - mServicePreferenceCategory = (PreferenceCategory) findPreference( - KEY_SERVICE_PREFERENCE_SECTION); - - mInteractorSummary = getActivity().getText( - R.string.voice_interactor_preference_summary); - mRecognizerSummary = getActivity().getText( - R.string.voice_recognizer_preference_summary); - mInteractorWarning = getActivity().getText(R.string.voice_interaction_security_warning); - } - - @Override - public void onStart() { - super.onStart(); - initSettings(); - } - - private void initSettings() { - mHelper = new VoiceInputHelper(getActivity()); - mHelper.buildUi(); - - mServicePreferenceCategory.removeAll(); - - if (mHelper.mCurrentVoiceInteraction != null) { - mCurrentKey = mHelper.mCurrentVoiceInteraction.flattenToShortString(); - } else if (mHelper.mCurrentRecognizer != null) { - mCurrentKey = mHelper.mCurrentRecognizer.flattenToShortString(); - } else { - mCurrentKey = null; - } - - for (int i=0; i<mHelper.mAvailableInteractionInfos.size(); i++) { - VoiceInputHelper.InteractionInfo info = mHelper.mAvailableInteractionInfos.get(i); - VoiceInputPreference pref = new VoiceInputPreference(getActivity(), info, - mInteractorSummary, mInteractorWarning, this); - mServicePreferenceCategory.addPreference(pref); - } - - for (int i=0; i<mHelper.mAvailableRecognizerInfos.size(); i++) { - VoiceInputHelper.RecognizerInfo info = mHelper.mAvailableRecognizerInfos.get(i); - VoiceInputPreference pref = new VoiceInputPreference(getActivity(), info, - mRecognizerSummary, null, this); - mServicePreferenceCategory.addPreference(pref); - } - } - - @Override - public Checkable getCurrentChecked() { - return mCurrentChecked; - } - - @Override - public String getCurrentKey() { - return mCurrentKey; - } - - @Override - public void setCurrentChecked(Checkable current) { - mCurrentChecked = current; - } - - @Override - public void setCurrentKey(String key) { - mCurrentKey = key; - for (int i=0; i<mHelper.mAvailableInteractionInfos.size(); i++) { - VoiceInputHelper.InteractionInfo info = mHelper.mAvailableInteractionInfos.get(i); - if (info.key.equals(key)) { - // Put the new value back into secure settings. - Settings.Secure.putString(getActivity().getContentResolver(), - Settings.Secure.VOICE_INTERACTION_SERVICE, key); - Settings.Secure.putString(getActivity().getContentResolver(), - Settings.Secure.VOICE_RECOGNITION_SERVICE, - new ComponentName(info.service.packageName, - info.serviceInfo.getRecognitionService()) - .flattenToShortString()); - return; - } - } - - for (int i=0; i<mHelper.mAvailableRecognizerInfos.size(); i++) { - VoiceInputHelper.RecognizerInfo info = mHelper.mAvailableRecognizerInfos.get(i); - if (info.key.equals(key)) { - Settings.Secure.putString(getActivity().getContentResolver(), - Settings.Secure.VOICE_INTERACTION_SERVICE, ""); - Settings.Secure.putString(getActivity().getContentResolver(), - Settings.Secure.VOICE_RECOGNITION_SERVICE, key); - return; - } - } - } - - @Override - public boolean onPreferenceClick(Preference preference) { - if (preference instanceof VoiceInputPreference) { - ((VoiceInputPreference)preference).doClick(); - } - return true; - } - - // For Search - public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider() { - - @Override - public List<SearchIndexableRaw> getRawDataToIndex(Context context, - boolean enabled) { - - List<SearchIndexableRaw> indexables = new ArrayList<>(); - - final String screenTitle = context.getString(R.string.voice_input_settings_title); - - SearchIndexableRaw indexable = new SearchIndexableRaw(context); - indexable.key = "voice_service_preference_section_title"; - indexable.title = context.getString(R.string.voice_service_preference_section_title); - indexable.screenTitle = screenTitle; - indexables.add(indexable); - - final List<ResolveInfo> voiceInteractions = - context.getPackageManager().queryIntentServices( - new Intent(VoiceInteractionService.SERVICE_INTERFACE), - PackageManager.GET_META_DATA); - - final int countInteractions = voiceInteractions.size(); - for (int i = 0; i < countInteractions; i++) { - ResolveInfo info = voiceInteractions.get(i); - VoiceInteractionServiceInfo visInfo = new VoiceInteractionServiceInfo( - context.getPackageManager(), info.serviceInfo); - if (visInfo.getParseError() != null) { - continue; - } - indexables.add(getSearchIndexableRaw(context, info, screenTitle)); - } - - final List<ResolveInfo> recognitions = - context.getPackageManager().queryIntentServices( - new Intent(RecognitionService.SERVICE_INTERFACE), - PackageManager.GET_META_DATA); - - final int countRecognitions = recognitions.size(); - for (int i = 0; i < countRecognitions; i++) { - ResolveInfo info = recognitions.get(i); - indexables.add(getSearchIndexableRaw(context, info, screenTitle)); - } - - return indexables; - } - - private SearchIndexableRaw getSearchIndexableRaw(Context context, - ResolveInfo info, String screenTitle) { - - ServiceInfo serviceInfo = info.serviceInfo; - ComponentName componentName = new ComponentName(serviceInfo.packageName, - serviceInfo.name); - - SearchIndexableRaw indexable = new SearchIndexableRaw(context); - indexable.key = componentName.flattenToString(); - indexable.title = info.loadLabel(context.getPackageManager()).toString(); - indexable.screenTitle = screenTitle; - - return indexable; - } - }; -} |