1 package com.android.settings.voice;
2 
3 import android.content.ComponentName;
4 import android.content.Context;
5 import android.provider.Settings;
6 import android.util.AttributeSet;
7 import android.view.View;
8 import android.view.ViewGroup;
9 import android.widget.ArrayAdapter;
10 import android.widget.ListAdapter;
11 
12 import com.android.settings.AppListPreferenceWithSettings;
13 import com.android.settings.R;
14 
15 import java.util.ArrayList;
16 import java.util.List;
17 
18 public class VoiceInputListPreference extends AppListPreferenceWithSettings {
19 
20     private VoiceInputHelper mHelper;
21 
22     // The assist component name to restrict available voice inputs.
23     private ComponentName mAssistRestrict;
24 
25     private final List<Integer> mAvailableIndexes = new ArrayList<>();
26 
VoiceInputListPreference(Context context, AttributeSet attrs)27     public VoiceInputListPreference(Context context, AttributeSet attrs) {
28         super(context, attrs);
29         setDialogTitle(R.string.choose_voice_input_title);
30     }
31 
32     @Override
createListAdapter()33     protected ListAdapter createListAdapter() {
34         return new CustomAdapter(getContext(), getEntries());
35     }
36 
37     @Override
persistString(String value)38     protected boolean persistString(String value) {
39         for (int i = 0; i < mHelper.mAvailableInteractionInfos.size(); ++i) {
40             VoiceInputHelper.InteractionInfo info = mHelper.mAvailableInteractionInfos.get(i);
41             if (info.key.equals(value)) {
42                 Settings.Secure.putString(getContext().getContentResolver(),
43                         Settings.Secure.VOICE_INTERACTION_SERVICE, value);
44                 Settings.Secure.putString(getContext().getContentResolver(),
45                         Settings.Secure.VOICE_RECOGNITION_SERVICE,
46                         new ComponentName(info.service.packageName,
47                                 info.serviceInfo.getRecognitionService())
48                                 .flattenToShortString());
49                 setSummary(getEntry());
50                 setSettingsComponent(info.settings);
51                 return true;
52             }
53         }
54 
55         for (int i = 0; i < mHelper.mAvailableRecognizerInfos.size(); ++i) {
56             VoiceInputHelper.RecognizerInfo info = mHelper.mAvailableRecognizerInfos.get(i);
57             if (info.key.equals(value)) {
58                 Settings.Secure.putString(getContext().getContentResolver(),
59                         Settings.Secure.VOICE_INTERACTION_SERVICE, "");
60                 Settings.Secure.putString(getContext().getContentResolver(),
61                         Settings.Secure.VOICE_RECOGNITION_SERVICE, value);
62                 setSummary(getEntry());
63                 setSettingsComponent(info.settings);
64                return true;
65             }
66         }
67 
68         setSettingsComponent(null);
69         return true;
70     }
71 
72     @Override
setPackageNames(CharSequence[] packageNames, CharSequence defaultPackageName)73     public void setPackageNames(CharSequence[] packageNames, CharSequence defaultPackageName) {
74         // Skip since all entries are created from |mHelper|.
75     }
76 
setAssistRestrict(ComponentName assistRestrict)77     public void setAssistRestrict(ComponentName assistRestrict) {
78         mAssistRestrict = assistRestrict;
79     }
80 
refreshVoiceInputs()81     public void refreshVoiceInputs() {
82         mHelper = new VoiceInputHelper(getContext());
83         mHelper.buildUi();
84 
85         final String assistKey =
86                 mAssistRestrict == null ? "" : mAssistRestrict.flattenToShortString();
87 
88         mAvailableIndexes.clear();
89         List<CharSequence> entries = new ArrayList<>();
90         List<CharSequence> values = new ArrayList<>();
91         for (int i = 0; i < mHelper.mAvailableInteractionInfos.size(); ++i) {
92             VoiceInputHelper.InteractionInfo info = mHelper.mAvailableInteractionInfos.get(i);
93             entries.add(info.appLabel);
94             values.add(info.key);
95 
96             if (info.key.contentEquals(assistKey)) {
97                 mAvailableIndexes.add(i);
98             }
99         }
100 
101         final boolean assitIsService = !mAvailableIndexes.isEmpty();
102         final int serviceCount = entries.size();
103 
104         for (int i = 0; i < mHelper.mAvailableRecognizerInfos.size(); ++i) {
105             VoiceInputHelper.RecognizerInfo info = mHelper.mAvailableRecognizerInfos.get(i);
106             entries.add(info.label);
107             values.add(info.key);
108             if (!assitIsService) {
109                 mAvailableIndexes.add(serviceCount + i);
110             }
111         }
112         setEntries(entries.toArray(new CharSequence[entries.size()]));
113         setEntryValues(values.toArray(new CharSequence[values.size()]));
114 
115         if (mHelper.mCurrentVoiceInteraction != null) {
116             setValue(mHelper.mCurrentVoiceInteraction.flattenToShortString());
117         } else if (mHelper.mCurrentRecognizer != null) {
118             setValue(mHelper.mCurrentRecognizer.flattenToShortString());
119         } else {
120             setValue(null);
121         }
122     }
123 
getCurrentService()124     public ComponentName getCurrentService() {
125         if (mHelper.mCurrentVoiceInteraction != null) {
126             return mHelper.mCurrentVoiceInteraction;
127         } else if (mHelper.mCurrentRecognizer != null) {
128             return mHelper.mCurrentRecognizer;
129         } else {
130             return null;
131         }
132     }
133 
134     private class CustomAdapter extends ArrayAdapter<CharSequence> {
135 
CustomAdapter(Context context, CharSequence[] objects)136         public CustomAdapter(Context context, CharSequence[] objects) {
137             super(context, com.android.internal.R.layout.select_dialog_singlechoice_material,
138                     android.R.id.text1, objects);
139         }
140 
141         @Override
areAllItemsEnabled()142         public boolean areAllItemsEnabled() {
143             return false;
144         }
145 
146         @Override
isEnabled(int position)147         public boolean isEnabled(int position) {
148             return mAvailableIndexes.contains(position);
149         }
150 
151         @Override
getView(int position, View convertView, ViewGroup parent)152         public View getView(int position, View convertView, ViewGroup parent) {
153             View view = super.getView(position, convertView, parent);
154             view.setEnabled(isEnabled(position));
155             return view;
156         }
157     }
158 }
159